一、先了解下Future:
1.实现Callable<Object>接口的任务,可通过Future获取返回值,其中Object是返回值类型,可以更替,举例如下。
public class Task implements Callable<Integer>{
private Integer source;
public Task(Integer source){
this.source = source;
}
@Override
public Integer call() throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getName());
switch (source){
case 1:{
Thread.sleep(1000);
return 1;
}
case 2:{
Thread.sleep(2000);
return 2;
}
case 3:{
Thread.sleep(3000);
return 3;
}
default:return 0;
}
}
}
2.可通过Future.get()阻塞获取返回值
二、多任务串行、利用Future计算任务执行结果的和
import java.util.concurrent.*;
/**
* 多任务,用时最小
*/
public class MultiTaskFutureGet {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10,
20,
100,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadPoolExecutor.AbortPolicy()); //拒绝策略
try {
Long start = System.currentTimeMillis();
/**
* 阻塞获取
*/
int sum = 0;
for (int i=1;i<4;i++){
sum+=executor.submit(new Task(i)).get();
}
System.out.println("多任务计算的和:"+sum);
System.out.println("总共消耗的时间:" + (System.currentTimeMillis()-start));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
输出如下(建议自己跑跑)
当前线程:pool-1-thread-1
当前线程:pool-1-thread-2
当前线程:pool-1-thread-3
多任务计算的和:6
总共消耗的时间:6005
可以清楚的看到任务是按提交顺序执行的,且是串行的。
三、多任务并行、利用invokeAll计算任务执行结果的和
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* 多任务,用时最小
*/
public class MultiTaskFutureGet {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10,
20,
100,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadPoolExecutor.AbortPolicy()); //拒绝策略
try {
Long start = System.currentTimeMillis();
/**
* 利用invokeAll同时执行所有线程
*/
List<Callable<Integer>> list = new ArrayList<>();
for (int i=3;i>0;i--){
list.add(new Task(i));
}
List<Future<Integer>> res = executor.invokeAll(list);
int sum = 0;
for (int i=0;i<3;i++){
int value = res.get(i).get();
System.out.println("第"+i +"个返回的任务id是:" + value);
sum+=value;
}
System.out.println("多任务计算的和:"+sum);
System.out.println("总共消耗的时间:" + (System.currentTimeMillis()-start));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
输出结果如下:
当前线程:pool-1-thread-3
当前线程:pool-1-thread-2
当前线程:pool-1-thread-1
第0个返回的任务id是:3
第1个返回的任务id是:2
第2个返回的任务id是:1
多任务计算的和:6
总共消耗的时间:3004
可以看到任务执行并发的,总耗时为最长任务执行时间。
!!!!并且这里需要注意的是,在res.get(i).get()时,会按list中任务添加顺序获取返回结果。也就是说即使最后提交的任务最先执行完毕,也只能最后获取!!!!
四、多任务并行、利用CompletionService计算任务执行结果的和,并优先获取最快执行完毕的任务返回值
import java.util.concurrent.*;
/**
* 多任务,用时最小,利用completionService实现
*
* 与 invokeAll不同的是,
* CompletionService.take().get()通过消息队列生产-消费模式获取最先执行完的结果,不会按提交顺序获取结果
*/
public class MultiTaskCompletionService {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10,
20,
100,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadPoolExecutor.AbortPolicy()); //拒绝策略
CompletionService<Integer> service = new ExecutorCompletionService<>(executor);
long start = System.currentTimeMillis();
for (int i =3;i>0;i--){
service.submit(new Task(i));
}
int sum=0;
for (int i =0;i<3;i++){
try {
int value = service.take().get();
System.out.println("第"+i +"个返回的任务id是:" + value);
sum+=value;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.println(sum);
System.out.println(System.currentTimeMillis()-start);
}
}
输出如下:
当前线程:pool-1-thread-2
当前线程:pool-1-thread-1
当前线程:pool-1-thread-3
第0个返回的任务id是:1
第1个返回的任务id是:2
第2个返回的任务id是:3
6
3002
可以看到CompletionService通过.take().get()可以不用考虑提交任务的顺序,会优先获取任务执行结束返回的值。因为CompletionService原理上是消息队列中的生产-消费模式,任务执行结束便将结果生产到队列中,然后利用.take().get()消费队列中的数据,从而优先获取已经执行完的任务返回值