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. Jvarkit : Java utilities for Bioinformatics

    Jvarkit : Java utilities for Bioinformatics :一个java写的生物信息工具包:http://lindenb.github.io/jvarkit/

  2. quota

    一.什么是磁盘配额 磁盘配额从字面意思上看就是给一个磁盘配置多少额度,而quota就是有多少限额的意思,所以总的来说就是限制用户对磁盘空间的使用量.因为Linux是多用户多任务的操作系统,许多人公用磁 ...

  3. shell 除法和格式化输出printf

    相关知识的补充: printf命令模仿C程序库里的printf()程序.printf由POSIX标准所定义,因此使用printf的脚本比使用echo有着更好的移植性. printf使用引用文本或者空格 ...

  4. Python函数之传参

    目录 1. 函数传参 1.1 参数的作用 1.2 形参和实参 1.3 位置参数 1.4 关键字参数 1.5 默认实参 1.6 参数总结 2. 可变参数 1. 函数传参 1.1 参数的作用 1.2 形参 ...

  5. 巩固javaweb的第二十天

    巩固内容: 同一个页面中的多个 form 在同一个页面中可以有多个 form 如果存在多个 form,那么提交信息的时候提交哪些信息,提交给哪个文件处理,这都 与提交按钮的位置有关.如果提交按钮在第一 ...

  6. nodeJs-Stream接口

    JavaScript 标准参考教程(alpha) 草稿二:Node.js Stream接口 GitHub TOP Stream接口 来自<JavaScript 标准参考教程(alpha)> ...

  7. C/C++ Qt 数据库与SqlTableModel组件应用

    SqlTableModel 组件可以将数据库中的特定字段动态显示在TableView表格组件中,通常设置QSqlTableModel类的变量作为数据模型后就可以显示数据表内容,界面组件中则通过QDat ...

  8. 理解各种不同含义的 new 和 delete

    new operator new操作符 operator new 操作符new placement new 定位new string *ps = new string("Memory Man ...

  9. 【Android】No Android SDK found(mac)+ 真机调试

     [1]No Android SDK found 如果没下载SDK,可以去google官方下载 如果因为上网问题,这里提供两个网址,有人整理好了,这里先谢谢他们,下面两个择其一下载 http://to ...

  10. How does “void *” differ in C and C++?

    C allows a void* pointer to be assigned to any pointer type without a cast, whereas C++ does not; th ...