当向线程池提交callable任务后,我们可能需要一次性获取所有返回结果,有三种处理方法。

方法一:自己维护返回结果

// 创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(10); // 存储执行结果的List
List<Future<String>> results = new ArrayList<Future<String>>(); // 提交10个任务
for ( int i=0; i<10; i++ ) {
Future<String> result = executorService.submit( new Callable<String>(){
public String call(){
int sleepTime = new Random().nextInt(1000);
Thread.sleep(sleepTime);
return "线程"+i+"睡了"+sleepTime+"秒";
}
} );
// 将执行结果存入results中
results.add( result );
} // 获取10个任务的返回结果
for ( int i=0; i<10; i++ ) {
// 获取包含返回结果的future对象
Future<String> future = results.get(i);
// 从future中取出执行结果(若尚未返回结果,则get方法被阻塞,直到结果被返回为止)
String result = future.get();
System.out.println(result);
}

此方法的弊端:

  1. 需要自己创建容器维护所有的返回结果,比较麻烦;
  2. 从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。

方法二:使用ExecutorService的invokeAll函数

本方法能解决第一个弊端,即并不需要自己去维护一个存储返回结果的容器。当我们需要获取线程池所有的返回结果时,只需调用invokeAll函数即可。
但是,这种方式需要你自己去维护一个用于存储任务的容器。

// 创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(10); // 创建存储任务的容器
List<Callable<String>> tasks = new ArrayList<Callable<String>>(); // 提交10个任务
for ( int i=0; i<10; i++ ) {
Callable<String> task = new Callable<String>(){
public String call(){
int sleepTime = new Random().nextInt(1000);
Thread.sleep(sleepTime);
return "线程"+i+"睡了"+sleepTime+"秒";
}
};
executorService.submit( task );
// 将task添加进任务队列
tasks.add( task );
} // 获取10个任务的返回结果
List<Future<String>> results = executorService.invokeAll( tasks ); // 输出结果
for ( int i=0; i<10; i++ ) {
// 获取包含返回结果的future对象
Future<String> future = results.get(i);
// 从future中取出执行结果(若尚未返回结果,则get方法被阻塞,直到结果被返回为止)
String result = future.get();
System.out.println(result);
}

方法三:使用CompletionService

CompletionService内部维护了一个阻塞队列,只有执行完成的任务结果才会被放入该队列,这样就确保执行时间较短的任务率先被存入阻塞队列中。

ExecutorService exec = Executors.newFixedThreadPool(10);

final BlockingQueue<Future<Integer>> queue = new LinkedBlockingDeque<Future<Integer>>(
10);
//实例化CompletionService
final CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(
exec, queue); // 提交10个任务
for ( int i=0; i<10; i++ ) {
executorService.submit( new Callable<String>(){
public String call(){
int sleepTime = new Random().nextInt(1000);
Thread.sleep(sleepTime);
return "线程"+i+"睡了"+sleepTime+"秒";
}
} );
} // 输出结果
for ( int i=0; i<10; i++ ) {
// 获取包含返回结果的future对象(若整个阻塞队列中还没有一条线程返回结果,那么调用take将会被阻塞,当然你可以调用poll,不会被阻塞,若没有结果会返回null,poll和take返回正确的结果后会将该结果从队列中删除)
Future<String> future = completionService.take();
// 从future中取出执行结果,这里存储的future已经拥有执行结果,get不会被阻塞
String result = future.get();
System.out.println(result);
}

Java并发编程的艺术(九)——批量获取多条线程的执行结果的更多相关文章

  1. 读《Java并发编程的艺术》(一)

    离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督 ...

  2. Java并发编程的艺术读书笔记(1)-并发编程的挑战

    title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...

  3. java并发编程的艺术(一)---锁的基本属性

    本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...

  4. 《Java并发编程的艺术》留给自己以后看的笔记

    <Java并发编程的艺术>这本书特别好,和<深入了解JAVA虚拟机>有一拼,建议做java的都看看,下面全部都是复制书中的部分内容,主要目的是做个笔记,方便以后遇到问题能找到. ...

  5. Java并发编程的艺术 记录(一)

    模拟死锁 package com.gjjun.concurrent; /** * 模拟死锁,来源于<Java并发编程的艺术> * @Author gjjun * @Create 2018/ ...

  6. 读书笔记之《Java 并发编程的艺术》

    一.多线程语义 即使是单核处理器也支持多线程执行代码,CPU 通过给每个线程分配 CPU 时间片来执行任务,当前任务执行一个时间片后会切换到下一个任务,所以 CPU 通过不停的切换线程执行. 并发执行 ...

  7. 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理

    二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...

  8. Java并发编程的艺术读书笔记(2)-并发编程模型

    title: Java并发编程的艺术读书笔记(2)-并发编程模型 date: 2017-05-05 23:37:20 tags: ['多线程','并发'] categories: 读书笔记 --- 1 ...

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

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

随机推荐

  1. 浏览器输入URL后发生了什么

    假如在浏览器中输入了www.cnblogs.com,然后回车 DNS解析 浏览器检查浏览器缓存是否有域名对应的IP. 浏览器查找操作系统是否有对应的DNS解析成果(hosts文件). 查找路由器缓存. ...

  2. CCF计算机职业资格认证考试题解

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF计算机职业资格认证考试题解 CCF计算机软件能力认证(简称CCF CSP认证)是CCF计算机职业资格认证系 ...

  3. Solr7.4.0的API(Solrj)操作

    一.SolrJ的概念 solr单机版服务搭建:https://www.cnblogs.com/frankdeng/p/9615253.html solr集群版服务搭建:https://www.cnbl ...

  4. 【PAT】1060 Are They Equal (25)(25 分)

    1060 Are They Equal (25)(25 分) If a machine can save only 3 significant digits, the float numbers 12 ...

  5. 【AtCoder】ARC103

    C - //// 为了防止一些多余的判断,我选择直接记录每个数的个数,然后枚举第一个数,找第一个数之外第二个数改变最少的情况下应该选什么 代码 #include <bits/stdc++.h&g ...

  6. MySQL查询语句执行过程及性能优化-基本概念和EXPLAIN语句简介

    网站或服务的性能关键点很大程度在于数据库的设计(假设你选择了合适的语言开发框架)以及如何查询数据上. 我们知道MySQL的性能优化方法,一般有建立索引.规避复杂联合查询.设置冗余字段.建立中间表.查询 ...

  7. codeforces_1092c

    title: codeforces_1092c date: 2018-12-24 19:42:23 tags: acm 刷题 概述 一道有关字符串前缀后缀的题,,,自己迟早要坑在这字符串的题上,,,一 ...

  8. 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 既然前后端 ...

  9. Linux驱动之USB(个人)

                              USB概述 <USB简介> a:背景 USB是Universal Serial Bus的缩写,是一种全新的,双向同步传输的,支持热插拔的 ...

  10. 【2017 4 24 - B】 组合数

    [题目描述] 输入格式: 一行一个正整数n 输出格式: 一行一个数f(n)对1000000007取余的值 [分析] 就是乱搞?? 就是问根到叶子有多少条路径嘛. 然后路径可以π.1.1.π...这样表 ...