转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/27250059

一般情况下,我们使用Runnable作为基本的任务表示形式,但是Runnable是一种有很大局限的抽象,run方法中只能记录日志,打印,或者把数据汇总入某个容器(一方面内存消耗大,另一方面需要控制同步,效率很大的限制),总之不能返回执行的结果;比如同时1000个任务去网络上抓取数据,然后将抓取到的数据进行处理(处理方式不定),我觉得最好的方式就是提供回调接口,把处理的方式最为回调传进去;但是现在我们有了更好的方式实现:CompletionService + Callable

Callable的call方法可以返回执行的结果;

CompletionService将Executor(线程池)和BlockingQueue(阻塞队列)结合在一起,同时使用Callable作为任务的基本单元,整个过程就是生产者不断把Callable任务放入阻塞对了,Executor作为消费者不断把任务取出来执行,并返回结果;

优势:

a、阻塞队列防止了内存中排队等待的任务过多,造成内存溢出(毕竟一般生产者速度比较快,比如爬虫准备好网址和规则,就去执行了,执行起来(消费者)还是比较慢的)

b、CompletionService可以实现,哪个任务先执行完成就返回,而不是按顺序返回,这样可以极大的提升效率;

1、CompletionService : Executor + BlockingQueue

下面看个例子:

  1. package com.zhy.concurrency.completionService;
  2. import java.util.Random;
  3. import java.util.concurrent.BlockingQueue;
  4. import java.util.concurrent.Callable;
  5. import java.util.concurrent.CompletionService;
  6. import java.util.concurrent.ExecutionException;
  7. import java.util.concurrent.ExecutorCompletionService;
  8. import java.util.concurrent.ExecutorService;
  9. import java.util.concurrent.Executors;
  10. import java.util.concurrent.Future;
  11. import java.util.concurrent.LinkedBlockingDeque;
  12. /**
  13. * 将Executor和BlockingQueue功能融合在一起,可以将Callable的任务提交给它来执行, 然后使用take()方法获得已经完成的结果
  14. *
  15. * @author zhy
  16. *
  17. */
  18. public class CompletionServiceDemo
  19. {
  20. public static void main(String[] args) throws InterruptedException,
  21. ExecutionException
  22. {
  23. /**
  24. * 内部维护11个线程的线程池
  25. */
  26. ExecutorService exec = Executors.newFixedThreadPool(11);
  27. /**
  28. * 容量为10的阻塞队列
  29. */
  30. final BlockingQueue<Future<Integer>> queue = new LinkedBlockingDeque<Future<Integer>>(
  31. 10);
  32. //实例化CompletionService
  33. final CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(
  34. exec, queue);
  35. /**
  36. * 模拟瞬间产生10个任务,且每个任务执行时间不一致
  37. */
  38. for (int i = 0; i < 10; i++)
  39. {
  40. completionService.submit(new Callable<Integer>()
  41. {
  42. @Override
  43. public Integer call() throws Exception
  44. {
  45. int ran = new Random().nextInt(1000);
  46. Thread.sleep(ran);
  47. System.out.println(Thread.currentThread().getName()
  48. + " 休息了 " + ran);
  49. return ran;
  50. }
  51. });
  52. }
  53. /**
  54. * 立即输出结果
  55. */
  56. for (int i = 0; i < 10; i++)
  57. {
  58. try
  59. {
  60. //谁最先执行完成,直接返回
  61. Future<Integer> f = completionService.take();
  62. System.out.println(f.get());
  63. } catch (InterruptedException e)
  64. {
  65. e.printStackTrace();
  66. } catch (ExecutionException e)
  67. {
  68. e.printStackTrace();
  69. }
  70. }
  71. exec.shutdown();
  72. }
  73. }

输出结果:

  1. pool-1-thread-4 休息了 52
  2. 52
  3. pool-1-thread-1 休息了 59
  4. 59
  5. pool-1-thread-10 休息了 215
  6. 215
  7. pool-1-thread-9 休息了 352
  8. 352
  9. pool-1-thread-5 休息了 389
  10. 389
  11. pool-1-thread-3 休息了 589
  12. 589
  13. pool-1-thread-2 休息了 794
  14. 794
  15. pool-1-thread-7 休息了 805
  16. 805
  17. pool-1-thread-6 休息了 909
  18. 909
  19. pool-1-thread-8 休息了 987
  20. 987

最先执行完成的直接返回,并不需要按任务提交的顺序执行,如果需要写个高并发的程序,且每个任务需要返回执行结果,这是个相当不错的选择!

2、ExecutorService.invokeAll

ExecutorService的invokeAll方法也能批量执行任务,并批量返回结果,但是呢,有个我觉得很致命的缺点,必须等待所有的任务执行完成后统一返回,一方面内存持有的时间长;另一方面响应性也有一定的影响,毕竟大家都喜欢看看刷刷的执行结果输出,而不是苦苦的等待;

下面看个例子:

  1. package com.zhy.concurrency.executors;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.Random;
  5. import java.util.concurrent.Callable;
  6. import java.util.concurrent.ExecutionException;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. import java.util.concurrent.Future;
  10. public class TestInvokeAll
  11. {
  12. public static void main(String[] args) throws InterruptedException,
  13. ExecutionException
  14. {
  15. ExecutorService exec = Executors.newFixedThreadPool(10);
  16. List<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>();
  17. Callable<Integer> task = null;
  18. for (int i = 0; i < 10; i++)
  19. {
  20. task = new Callable<Integer>()
  21. {
  22. @Override
  23. public Integer call() throws Exception
  24. {
  25. int ran = new Random().nextInt(1000);
  26. Thread.sleep(ran);
  27. System.out.println(Thread.currentThread().getName()+" 休息了 " + ran );
  28. return ran;
  29. }
  30. };
  31. tasks.add(task);
  32. }
  33. long s = System.currentTimeMillis();
  34. List<Future<Integer>> results = exec.invokeAll(tasks);
  35. System.out.println("执行任务消耗了 :" + (System.currentTimeMillis() - s) +"毫秒");
  36. for (int i = 0; i < results.size(); i++)
  37. {
  38. try
  39. {
  40. System.out.println(results.get(i).get());
  41. } catch (Exception e)
  42. {
  43. e.printStackTrace();
  44. }
  45. }
  46. exec.shutdown();
  47. }
  48. }

执行结果:

  1. pool-1-thread-10 休息了 1
  2. pool-1-thread-5 休息了 59
  3. pool-1-thread-6 休息了 128
  4. pool-1-thread-1 休息了 146
  5. pool-1-thread-3 休息了 158
  6. pool-1-thread-7 休息了 387
  7. pool-1-thread-9 休息了 486
  8. pool-1-thread-8 休息了 606
  9. pool-1-thread-4 休息了 707
  10. pool-1-thread-2 休息了 817
  11. 执行任务消耗了 :819毫秒
  12. 146
  13. 817
  14. 158
  15. 707
  16. 59
  17. 128
  18. 387
  19. 606
  20. 486
  21. 1

我特意在任务提交完成打印了一个时间,然后invokeAll执行完成后打印了下时间,可以看出invokeAll返回是等待所有线程执行完毕的。这点来说,我觉得可用性不如CompletionService。

嗯,对于批量执行任务,且携带返回结果的案例就到这里~如果有疑问或者代码中存在错误请指出~

Java并发专题 带返回结果的批量任务执行的更多相关文章

  1. Java并发专题 带返回结果的批量任务执行 CompletionService ExecutorService.invokeAll(转)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/27250059 一般情况下,我们使用Runnable作为基本的任务表示形式,但是R ...

  2. Java并发专题 带返回结果的批量任务运行 CompletionService ExecutorService.invokeAll

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/27250059 普通情况下,我们使用Runnable作为主要的任务表示形式,可是R ...

  3. 带返回结果的批量任务执行 CompletionService

    转自 :http://blog.csdn.net/lmj623565791/article/details/27250059 一般情况下,我们使用Runnable作为基本的任务表示形式,但是Runna ...

  4. Java 并发专题 :FutureTask 实现预加载数据 在线看电子书、浏览器浏览网页等

    继续并发专题~ FutureTask 有点类似Runnable,都可以通过Thread来启动,不过FutureTask可以返回执行完毕的数据,并且FutureTask的get方法支持阻塞. 由于:Fu ...

  5. Java 并发专题 : CyclicBarrier 打造一个安全的门禁系统

    继续并发专题~ 这次介绍CyclicBarrier:看一眼API的注释: /** * A synchronization aid that allows a set of threads to all ...

  6. Java 并发专题 : Semaphore 实现 互斥 与 连接池

    继续并发方面的知识.今天介绍Semaphore,同样在java.util.concurrent包下. 本来准备通过例子,从自己实现到最后使用并发工具实现,但是貌似效果并不是很好,有点太啰嗦的感觉,所有 ...

  7. Java 并发专题 :闭锁 CountDownLatch 之一家人一起吃个饭

    最近一直整并发这块东西,顺便写点Java并发的例子,给大家做个分享,也强化下自己记忆. 每天起早贪黑的上班,父母每天也要上班,话说今天定了个饭店,一家人一起吃个饭,通知大家下班去饭店集合.假设:3个人 ...

  8. 那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结

    <Java并发编程实战>和<Java并发编程的艺术>           Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用 ...

  9. java并发编程实战:第六章----任务执行

    任务:通常是一些抽象的且离散的工作单元.大多数并发应用程序都是围绕"任务执行"来构造的,把程序的工作分给多个任务,可以简化程序的组织结构便于维护 一.在线程中执行任务 任务的独立性 ...

随机推荐

  1. 第一个Mac程序——倒计时v1&v2

    先放效果图: 这是我第一次尝试在Mac平台下编程,之前学过几天IOS开发,一直在等MJ老师更新.闲下来不编程不舒服,给自己,也给老婆编了这个以提醒自己好好学习.v2版加入了各种倒计时.改进了界面.把倒 ...

  2. 为什么Linux的Fdisk分区时First Sector为2048?

    是为EFI启动预留的,而Fdisk也随着这波的兴起而跟着变. 参考: http://homepage.ntlworld.com./jonathan.deboynepollard/FGA/disc-pa ...

  3. Matlab中find函数陷阱

    a = [ 1 2 3 3  3]; 如果a==3 返回[ 0 0 1  1 1]; find(a==3) 返回[3 4 5],这才是想要的下标.

  4. Android简单的利用MediaRecorder进行录音的实例代码

    MainActivity.java package com.example.soundrecord_demo; import java.io.IOException; import android.m ...

  5. js延时函数setTimeout

    实现一个延时执行的效果,现记录如下: <html> <head> <script type="text/javascript" src="/ ...

  6. 关于BufferedInputStream和BufferedOutputStream的实现原理的理解

    在介绍FileInputStream和FileOutputStream的例子中,使用了一个byte数组来作为数据读入的缓冲区,以文件存取为例,硬盘存取的速度远低于内存中的数据存取速度.为了减少对硬盘的 ...

  7. http://www.cnblogs.com/dolphin0520/p/3949310.html

    http://www.cnblogs.com/dolphin0520/p/3949310.html

  8. Linux增加挂载盘

    命令:fdisk /dev/sdb, m 命令:m,n,e,1,p,w 命令:mkfs -t ext4 /dev/sdb,y 挂载命令:mount -t ext4 /dev/sdb /data 获取U ...

  9. Sending SMS And Dialing Numbers without User Consent(Context is not needed)

    Sending SMS And Dialing Numbers without User Consent Sending SMS does not require context or user in ...

  10. Highcharts使用二维数组生成图表

    Highcharts使用二维数组生成图表 二维数组是更为灵活的一种数据存储方式.在Highcharts中.能够使用配置项column和rows二维数组.对于使用columns构建的二维数组,Highc ...