Java中ExecutorService和CompletionService区别
我们现在在Java中使用多线程通常不会直接用Thread对象了,而是会用到java.util.concurrent包下的ExecutorService类来初始化一个线程池供我们使用。
之前我一直习惯自己维护一个list保存submit的callable task所返回的Future对象。
在主线程中遍历这个list并调用Future的get()方法取到Task的返回值。
public class CompletionServiceTest {
static class Task implements Callable<String>{
private int i;
public Task(int i){
this.i = i;
}
@Override
public String call() throws Exception {
Thread.sleep(10000);
return Thread.currentThread().getName() + "执行完任务:" + i;
}
}
public static void main(String[] args){
testUseFuture();
}
private static void testUseFuture(){
int numThread = 5;
ExecutorService executor = Executors.newFixedThreadPool(numThread);
List<Future<String>> futureList = new ArrayList<Future<String>>();
for(int i = 0;i<numThread;i++ ){
Future<String> future = executor.submit(new CompletionServiceTest.Task(i));
futureList.add(future);
}
while(numThread > 0){
for(Future<String> future : futureList){
String result = null;
try {
result = future.get(0, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
//超时异常直接忽略
}
if(null != result){
futureList.remove(future);
numThread--;
System.out.println(result);
//此处必须break,否则会抛出并发修改异常。(也可以通过将futureList声明为CopyOnWriteArrayList类型解决)
break;
}
}
}
}
}
但是,我在很多地方会看到一些代码通过CompletionService包装ExecutorService,然后调用其take()方法去取Future对象。
public class CompletionServiceTest {
static class Task implements Callable<String>{
private int i;
public Task(int i){
this.i = i;
}
@Override
public String call() throws Exception {
Thread.sleep(10000);
return Thread.currentThread().getName() + "执行完任务:" + i;
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException{
testExecutorCompletionService();
}
private static void testExecutorCompletionService() throws InterruptedException, ExecutionException{
int numThread = 5;
ExecutorService executor = Executors.newFixedThreadPool(numThread);
CompletionService<String> completionService = new ExecutorCompletionService<String>(executor);
for(int i = 0;i<numThread;i++ ){
completionService.submit(new CompletionServiceTest.Task(i));
}
}
for(int i = 0;i<numThread;i++ ){
System.out.println(completionService.take().get());
}
}
以前没研究过这两者之间的区别。今天看了源代码之后就明白了。
这两者最主要的区别在于submit的task不一定是按照加入自己维护的list顺序完成的。
从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。
而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。
所以,先完成的必定先被取出。这样就减少了不必要的等待时间
Java中ExecutorService和CompletionService区别的更多相关文章
- ExecutorService和CompletionService区别
ExecutorService和CompletionService区别: ExecutorService:一直习惯自己维护一个list保存submit的callable task所返回的Future对 ...
- java中ArrayList 、LinkList区别
转自:http://blog.csdn.net/wuchuanpingstone/article/details/6678653 个人建议:以下这篇文章,是从例子说明的方式,解释ArrayList.L ...
- java 中 ==和equals 的区别
Java中equals和==的区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boolea ...
- java中equals和==的区别 (转)
java中equals和==的区别 值类型是存储在内存中的堆栈(以后简称栈),而引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中. ==操作比较的是两个变量的值是否相等,对于引 ...
- 【转】Java中equals和==的区别
[转]Java中equals和==的区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boole ...
- java中a++与++a区别
java中a++与++a区别 a++与++a的区别,如果单独使用没有任何区别,如果在运算中就有区别了,a++是先运算在赋值,而++a是先赋值在运算!! 先看a++的代码哦 class demo1 { ...
- c#与java中byte字节的区别及转换方法
原文:c#与java中byte字节的区别及转换方法 在java中 byte的范围在 [-128,127] 在C#中 byte的范围在 [0,255] 所以 java程序与C#程序 进行数据传输的时 ...
- java中==与equel的区别
值类型是存储在内存中的堆栈(以后简称栈),而引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中. ==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地 ...
- Java中的“&”和“&&”的区别
Java中的"&"和"&&"的区别 1."&"是位运算符,"&&"是逻辑 ...
随机推荐
- 影响 PHP 行为的扩展和网络函数
<?php /* * * 影响 PHP 行为的扩展 * PHP 选项和信息 * * assert_options — 设置/获取断言的各种标志 assert — 检查一个断言是否为 FALSE ...
- ArGIS Server 服务的更新
对于普通地图服务更新 [产品版本]:arcgis for server 10.1,10.1 sp1,10.2及以上 [问题分析]: 由于在10.1中地图服务的发布采用的是msd的形式,也就是虽然在Ar ...
- 理解Bitcode
用Xcode 7 beta 3在真机(iOS 8.3)上运行一下我们的工程,结果发现工程编译不过.看了下问题,报的是以下错误: 1 ld: ‘/Users/**/Framework/SDKs/Poly ...
- Multi-level Multi-select plugin
Property file: Country[tab]City United States[tab]San Francisco United States[tab]Chicago Mexico[tab ...
- Nest查询示例
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Hadoop离线项目介绍(不包括程序)
一:项目场景 1.需求分析 根据用户行为数据进行程序的处理,得到结果保存到关系型数据库中 需要收集用户(系统使用者)在不同客户端上产生的用户行为数据,最终保存到hdfs上 需要明确收集字段的相关信息, ...
- 【C语言学习笔记】存储类、链接和内存管理
因为对内存管理部分一直没有很清楚的思路,所以一直在找资料想系统看一下这部分的内容.在C primer plus里看到了这一章,虽然大多都是心知肚明的东西,但是还是很多概念性系统性的东西让我眼前一亮,把 ...
- Docker的私有仓库
server 192.168.1.107 registry ---push client 192.168.1.103 --pull [192.168.1.107 ...
- [Android Tips] 8. Install apk on multiple connected devices
$ adb devices | | | xargs -I X adb -s X install pathto/myapp-release.apk
- 20145320《Java程序设计》第4周学习总结
20145320<Java程序设计>第4周学习总结 教材学习内容总结 第六章 继承与多态 继承 继承作为面向对象的第二大特征,避免多个类间重复定义共同行为.即当多个类中存在相同属性和行为时 ...