对CompletionService封装,实现快速处理业务任务并汇总结果
来源:互联网 发布:潘石屹 三段婚姻 知乎 编辑:程序博客网 时间:2024/06/05 20:20
业务需要,比如计算每个用户收益的job,计算每个用户收益是一个任务会被丢到线程池。对于每个任务,需要在最后根据任务结果进行汇总统计,有多少用户的收益计算任务是失败的。
jdk的CompletionService实现,让开发者提交任务到线程池,然后任务执行完后会放到一个结果队列中,最后可以通过getResult方法从结果队列中取,然后进行统计。这种缺点是只有等所有任务提交到线程池了最后才能进行对每个任务结果汇总。
通过await及signal可以解决这个问题。基本原理是定义一个count记录当前任务数,生产者每提交一个业务任务到线程池count就加1. 起一个消费者线程不断查看count值如果为0说明无数据进行await,有数据则马上进行处理。消费者await后,生产者提交任务后,发现队列大小1,说明之前队列为空的时候消费者可能已经await了,这时马上去唤醒消费者。
代码:
package concurrent;import java.util.concurrent.Callable;import java.util.concurrent.CompletionService;import java.util.concurrent.ExecutorCompletionService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Future;import java.util.concurrent.atomic.AtomicLong;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import junit.framework.Assert;/** * * 利用await及notify实现的CompletionService封装类,提高处理速度<br/> * * 例:<br/> * * <pre> * 1.定义执行业务任务浅程池 ExecutorService executorService = * Executors.newFixedThreadPool(50); * * 2.创建快速处理器,传入执行业务线程池,及汇总业务处理结果处理类 final QuickProcessByNotify<String, Long> * quickProcess = new QuickProcessByNotify<String, Long>(executorService, new QuickTaskResultHandler<String, Long>() {<br/> * <em>//业务结果汇总处理类,这里最终汇总结果是long类型的成功数successCount<br/> * private AtomicLong successCount = new AtomicLong(0); * * public void handle(Future<String> future) { //这里放业务汇总逻辑 } * * public Long getResult() { //返回业务汇总结果 return successCount.get(); } * }); * * 3.调用processByCallBack方法,开始查询业务数据并处理 * * long allCount = quickProcess.processByCallBack(new * QuickBizProcessCallbak() { * //QuickBizProcessCallbak是业务处理回调接口,业务方实现此接口 * public void doBiz() { quickProcess.submit(new Callable<String>() { * //一定要提交业务任务到快速处理器 public String call() throws Exception { * return "success"; } }); } }); * * <pre/> * * @author shenxiu * * @param <T> * @param <R> */public class QuickProcessByNotify<T/* 业务任务处理结果类型 */, R/* 最终汇总的结果类型 */> implements QuickProcessService<T, R> {private static final Logger logger = LoggerFactory.getLogger(QuickProcessByNotify.class);/** * 发送者发送完标记 */private volatile boolean sendFinishFlag;private CompletionService<T> quickCompletionService;private Lock lock = new ReentrantLock();private Condition notEmptyCondition = lock.newCondition();private AtomicLong countShouldProcess = new AtomicLong(0);/** * 当前处理器状态<br/> * */private volatile int state;private static int RUNNING_STATE = 0;private static int TERMINATE_STATE = 1;/** * 消费者线程 */private Thread consumeThread;/** * 业务方实现结果处理类 */private QuickTaskResultHandler<T, R> taskResultHandler;public QuickProcessByNotify(CompletionService<T> quickCompletionService,QuickTaskResultHandler<T, R> taskResultHandler) {this.quickCompletionService = quickCompletionService;this.taskResultHandler = taskResultHandler;}public QuickProcessByNotify(ExecutorService executorService, QuickTaskResultHandler<T, R> taskResultHandler) {quickCompletionService = new ExecutorCompletionService<T>(executorService);this.taskResultHandler = taskResultHandler;}public void submit(Callable<T> task) {quickCompletionService.submit(task);long cnt = countShouldProcess.incrementAndGet();if (cnt == 1) {this.notifyConsumer();}}/** * 消费者消费任务结果runable * * @author shenxiu * */class DefaultConsumeTask implements Runnable {public void run() {long count;while (true) {/** * 1.判断退出条件<br/> * 若sendFinishFlag为true, * 则发送方之前在做submit的时候肯定会先增加countShouldProcess值<br/> * 也就是countShouldProcess的值变化先行发生于sendFinishFlag值的变化<br/> * 因此不会发生sendFinishFlag为true,但消费者看到的countShouldProcess为0, * 实际有消息未处理的情况 */if (sendFinishFlag && countShouldProcess.get() <= 0) {/** * 发送方已经发送完数据,且消费队列没有数据了 */break;}lock.lock();try {/** * 2. 发送方未发送完数据,但消费队列还没有数据,await下,这里加锁防止以下情况:<br/> * 消费者在判断sendFinishFlag的条件,看到的是false, * 然后也看到countShouldProcess值为0<br/> * 消费者在要做await时,未加锁的情况下生产者将sendFinishFlag设置为true了, * 这时消费者接着await,然后消费者就永远处理await了。 */if (!sendFinishFlag && countShouldProcess.get() <= 0) {notEmptyCondition.await();}} catch (InterruptedException e) {logger.error("quickProcessByNotify consumer thread,InterruptedException", e);} finally {lock.unlock();}/** * 3.有数据,取出处理 */count = countShouldProcess.get();for (int i = 0; i < count; i++) {try {Future<T> future = quickCompletionService.take();taskResultHandler.handle(future);} catch (InterruptedException e) {logger.error("InterruptedException err");} finally {countShouldProcess.decrementAndGet();}}}// 消费者正常退出了,设置state为TERMIATEstate = TERMINATE_STATE;}}public void waitProcessResult() throws InterruptedException {consumeThread.join();}public void notifyConsumer() {try {lock.lock();notEmptyCondition.signal();// System.out.println("===sig");} finally {lock.unlock();}}public void setSendFinishFlagToTrue() {try {lock.lock();sendFinishFlag = true;notEmptyCondition.signal();} finally {lock.unlock();}}public void shutdownNow() {try {lock.lock();if (state == TERMINATE_STATE) {/** * 当前消费者已经退出 */return;}/** * 否则强制退出 */logger.error("err consume thread not stop,shutdownNow");sendFinishFlag = true;countShouldProcess.addAndGet(-1);notEmptyCondition.signal();consumeThread.interrupt();} catch (Exception e) {logger.error("shutdown err", e);} finally {lock.unlock();}}public void setTaskResultHandler(QuickTaskResultHandler<T, R> taskResultHandler) {this.taskResultHandler = taskResultHandler;}public R getResult() {return taskResultHandler.getResult();}public void start() {Assert.assertNotNull(quickCompletionService);Assert.assertNotNull(taskResultHandler);consumeThread = new Thread(new DefaultConsumeTask());consumeThread.start();state = RUNNING_STATE;}public R processByCallBack(QuickBizProcessCallbak bizProcessCallbak) {try {// 1.开启处理器this.start();// 2.执行业务逻辑bizProcessCallbak.doBiz();System.out.println("before:" + getResult());// 3.业务数据都发送完了,设置sendFinishFlag为truethis.setSendFinishFlagToTrue();// 3.等待consumeThread消费consumeThread.join();System.out.println("after:" + getResult());// 4.返回结果return this.getResult();} catch (Exception e) {logger.error(">processByCallBack err", e);} finally {// 非正常情况下关闭消费者线程this.shutdownNow();}return this.getResult();}}
1 0
- 对CompletionService封装,实现快速处理业务任务并汇总结果
- 线程池实现,并通过CompletionService,来实现反馈处理
- CompletionService 创建多线程,并返回全部线程处理结束后的结果
- CompletionService + Callable实现线程动态返回结果
- (android实战)线程池实现,并通过CompletionService,来实现反馈处理(转载)
- 执行器实现返回多个任务并处理第一个结果
- 带返回结果的批量任务执行 CompletionService ExecutorService.invokeAll
- 【Java并发】- 使用CompletionService异步收集任务结果
- Callable和Future实现调用任务并返回结果数据
- Callable和Future实现调用任务并返回结果数据
- 使用CompletionService批处理任务
- 使用CompletionService批处理任务
- 使用CompletionService批处理任务
- Java并发专题 带返回结果的批量任务执行 CompletionService ExecutorService.invokeAll
- Java并发专题 带返回结果的批量任务执行 CompletionService ExecutorService.invokeAll
- Java并发专题 带返回结果的批量任务执行 CompletionService
- Java并发专题 带返回结果的批量任务执行 CompletionService ExecutorService.invokeAll
- 多线程并发执行任务,取结果归集。终极总结:Future、FutureTask、CompletionService、CompletableFuture
- android shape的使用
- 支持向量机系列三:Kernel
- 将DPDK移植到snort上的DAQ
- 开发应该做好自测
- 多重部分和问题
- 对CompletionService封装,实现快速处理业务任务并汇总结果
- 支持向量机系列四:Outliers
- 单调递增最长子序列
- MongoDB权限管理之用户名和密码的操作
- 结构体内存对齐的补充说明与总结
- HDU 5795 A Simple Nim SG函数打表找规律
- 支持向量机系列五:Numerical Optimization
- MongoDB增加用户认证: 增加用户、删除用户、修改用户密码、读写权限、只读权限
- 纪念帖