CompletionService使用
接口
CompletionService
的功能是以异步的方式一边生产新的任务,一边处理已完成的任务的结果。这样可以将执行任务与处理处理分离开来处理。使用submit执行任务,使用take取得已经完成的任务
CompletionService,内部使用Executor框架和BlockingQueue来实现的
public class MyCallable implements Callable<String> {
private String username;
private long sleepValue;
public MyCallable(String username, long sleepValue) {
this.username = username;
this.sleepValue = sleepValue;
}
@Override
public String call() throws Exception {
System.out.println(username);
Thread.sleep(sleepValue);
// if ("userName3".equals(username)){
// throw new Exception("自己抛出异常了");
// }
return "return: "+ username;
}
}
测试:
@Test
public void testMyCallable() throws InterruptedException {
try {
List<MyCallable> list = new ArrayList<>();
for (int i=1; i<=5; i++){
MyCallable myCallable = new MyCallable("userName"+i, i*1000);
list.add(myCallable);
}
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,
5, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
CompletionService completionService = new ExecutorCompletionService(executor);
for (int i=0; i<5; i++){
completionService.submit(list.get(i));
}
for (int i=0; i<5; i++){
System.out.println("等待打印"+(i+1)+"个返回值");
System.out.println(completionService.take().get());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Thread.sleep(3000);
}
结果:
userName1
userName3
userName2
等待打印1个返回值
userName4
userName5
return: userName1
等待打印2个返回值
return: userName2
等待打印3个返回值
return: userName3
等待打印4个返回值
return: userName4
等待打印5个返回值
return: userName5
如果放开注释:
等待打印1个返回值
userName1
userName2
userName3
userName4
userName5
return: userName1
等待打印2个返回值
return: userName2
等待打印3个返回值
java.util.concurrent.ExecutionException: java.lang.Exception: 自己抛出异常了
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at com.github.vspro.concurrent.MyCallableTest.testMyCallable(MyCallableTest.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
Caused by: java.lang.Exception: 自己抛出异常了
at com.github.vspro.concurrent.MyCallable.call(MyCallable.java:21)
at com.github.vspro.concurrent.MyCallable.call(MyCallable.java:5)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
可以看到,如果抛出异常,后面的计算结果都获取不到了