import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*; /**
* 以下是伪代码,要根据自己的实际逻辑进行整合
*/
@Service
public class PushProcessServiceImpl implements PushProcessService { private final static Logger logger = LoggerFactory.getLogger(PushProcessServiceImpl.class); /**
*每个线程更新的条数
* 这表示每次执行五千条数据的推送操作
*/
private static final Integer LIMIT = 5000; /**
* 起的线程数
*/
private static final Integer THREAD_NUM = 5; /**
* 创建线程池
*
* - corePoolSize:线程核心参数选择了5
*
* - maximumPoolSize:最大线程数选择了核心线程数2倍数
*
* - keepAliveTime:非核心闲置线程存活时间直接置为0
*
* - unit:非核心线程保持存活的时间选择了 TimeUnit.SECONDS 秒
*
* - workQueue:线程池等待队列,使用 容量初始为100的 LinkedBlockingQueue阻塞队列
*
* 线程池拒绝策略,采用了默认AbortPolicy:直接丢弃任务,抛出异常。
*
*/
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREAD_NUM, THREAD_NUM * 2, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100)); /**
* 执行推送任务
* @throws ExecutionException
* @throws InterruptedException
*/
public void pushData() throws ExecutionException, InterruptedException {
//计数器,需要保证线程安全
int count = 0; //这里从数据库查询出要推送数据总数,根据自己实际的来
Integer total = pushProcessMapper.getCountByState(0); logger.info("未推送数据条数:{}", total);
//计算需要循环多少轮
int num = total / (LIMIT * THREAD_NUM) + 1;
logger.info("要经过的轮数:{}", num); //统计总共推送成功的数据条数
int totalSuccessCount = 0;
for (int i = 0; i < num; i++) {
//使用集合来接收线程的运行结果,防止阻塞,接收线程返回结果
List<Future<Integer>> futureList = new ArrayList<>(32); //起THREAD_NUM个线程并行查询更新库,加锁
for (int j = 0; j < THREAD_NUM; j++) {
//使用 synchronized 来保证线程安全,保证计数器的增加是有序的
synchronized (PushProcessServiceImpl.class) {
int start = count * LIMIT;
count++;
/**
* 提交线程,用数据起始位置标识线程
* 这里前两个参数start和limit参数相当于执行sql
* limit start,limit
*
*/ Future<Integer> future = pool.submit(new PushDataTask(start, LIMIT, start));
//先不取值,防止阻塞,放进集合
futureList.add(future);
}
}
//统计本轮推送成功数据
for (Future f : futureList) {
totalSuccessCount = totalSuccessCount + (int) f.get();
}
}
//把数据库的推送标识更新为已推送(已推送!=推送成功),可以根据自己实际的来
pushProcessMapper.updateAllState(1); logger.info("推送数据完成,需推送数据:{},推送成功:{}", total, totalSuccessCount);
} /**
* 推送数据线程类
*/
class PushDataTask implements Callable<Integer> {
int start;
int limit;
int threadNo; //线程编号 PushDataTask(int start, int limit, int threadNo) {
this.start = start;
this.limit = limit;
this.threadNo = threadNo;
} @Override
public Integer call() throws Exception {
int count = 0;
//分页查询每次执行的推送的数据,查询数据
List<PushProcess> pushProcessList = pushProcessMapper.findPushRecordsByStateLimit(0, start, limit);
if (CollectionUtils.isEmpty(pushProcessList)) {
return count;
}
logger.info("线程{}开始推送数据", threadNo); /**
* 遍历需要更新的数据实体类
*/
for (PushProcess process : pushProcessList) {
//这里是执行推送请求,根据自己实际的来,也可以要处理的任务
boolean isSuccess = pushUtil.sendRecord(process); //根据主键更新推送是否成功状态标识
if (isSuccess) {
//推送成功
pushProcessMapper.updateFlagById(process.getId(), 1);
count++;
} else {
//推送失败
pushProcessMapper.updateFlagById(process.getId(), 2);
}
}
logger.info("线程{}推送成功{}条", threadNo, count);
return count;
}
}
}

JAVA使用多线程进行数据处理的更多相关文章

  1. Java的多线程机制系列:不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

  2. java之多线程 二

    线程的生命周期: 当线程被创建并被启动时,它既不是一启动就进入了执行状态,在线程的生命周期中,它要经过new(新建),就绪(Runnable),运行(Running),阻塞(Blocked),dead ...

  3. Java的多线程机制系列:(一)总述及基础概念

    前言 这一系列多线程的文章,一方面是个人对Java现有的多线程机制的学习和记录,另一方面是希望能给不熟悉Java多线程机制.或有一定基础但理解还不够深的读者一个比较全面的介绍,旨在使读者对Java的多 ...

  4. Java Thread 多线程 介绍

    1.线程概述 几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程. 当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程. 2.线程 ...

  5. Java:多线程<一>

    程序运行时,其实是CPU在执行程序的进程,为了提高工作效率一个进程可以有多个线程. Java的多线程: 其实我们之前就见过Java的线程,main就是Java的一个线程,还有另一个条线程总是和main ...

  6. Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

  7. Java的多线程机制系列:(三)synchronized的同步原理

    synchronized关键字是JDK5之实现锁(包括互斥性和可见性)的唯一途径(volatile关键字能保证可见性,但不能保证互斥性,详细参见后文关于vloatile的详述章节),其在字节码上编译为 ...

  8. Java基础——多线程

    Java中多线程的应用是非常多的,我们在Java中又该如何去创建线程呢? http://www.jianshu.com/p/40d4c7aebd66 一.常用的有三种方法来创建多线程 新建一个类继承自 ...

  9. JAVA之多线程的创建

    转载请注明源出处:http://www.cnblogs.com/lighten/p/5967853.html 1.概念 老调重弹,学习线程的时候总会牵扯到进程的概念,会对二者做一个区分.网上有较多的解 ...

随机推荐

  1. Codeforces 1276D - Tree Elimination(树形 dp)

    Codeforces 题面传送门 & 洛谷题面传送门 繁琐的简单树形 dp(大雾),要是现场肯定弃了去做 F 题 做了我一中午,写篇题解纪念下. 提供一种不太一样的思路. 首先碰到这样的题肯定 ...

  2. 【GS文献】全基因组选择模型研究进展及展望

    目录 1. GS概况 2. GS模型 1)直接法 GBLUP 直接法的模型改进 ①单随机效应 ②多随机效应 2)间接法 间接法模型 基于间接法的模型改进 3. GS模型比较 模型比较结论 4.问题及展 ...

  3. R语言与医学统计图形-【29】地图的绘制

    R绘制地图原理: R使用一个个多边形(polygon)来表示每个区域,通过顺次连接GIS数据提供的每个区域多边形的坐标来逐点绘制这些多边形,所以理论上只要得到GIS数据就可绘制相应的地图. 地图绘制说 ...

  4. 在R语言中使用Stringr进行字符串操作

    今天来学习下R中字符串处理操作,主要是stringr包中的字符串处理函数的用法. 先导入stringr包,library(stringr),require(stringr),或者stringr::函数 ...

  5. Redis——面试官考题

    总结: 本文在一次面试的过程中讲述了 Redis 是什么,Redis 的特点和功能,Redis 缓存的使用,Redis 为什么能这么快,Redis 缓存的淘汰策略,持久化的两种方式,Redis 高可用 ...

  6. Mac下source tree 下的安装

    安装时出现了以下错误,解决方法 git -c diff.mnemonicprefix=false -c core.quotepath=false -c credential.helper=source ...

  7. Android editttext只能输入不能删除(选中后被软键盘遮住)

    感谢https://www.dutycode.com/post-20.html: 解决方法:在布局外外嵌一层scrollview.

  8. 日常Java 2021/10/21

    Java Iterator(迭代器) 如果需要使用iterator类需要从java.util包中引入它 Java Iterator不是一个集合,它是一种访问集合的方法,用于迭代ArrayList和Ha ...

  9. academy

    academy at/in school都行,academy一般用at. The word comes from the Academy in ancient Greece, which derive ...

  10. Angular中怎样创建service服务来实现组件之间调用公共方法

    Angular组件之间不能互相调用方法,但是可以通过创建服务来实现公共方法的调用. 实现 创建服务命令 ng g service 服务路径/服务名 比如这里在app/services目录下创建stor ...