携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情
使用CompletionService解决Future的缺点
接口Future具有阻塞同步性,这种情况代码运行效率很低,可以使用CompletionService接口解决Future同步阻塞的缺点。
使用CompletionService接口中的take()方法,它的主要作用是取得Future对象,方法声明结构如下:
public Future take() throws InterruptedException
线程执行代码如下:
@Slf4j
public class FutureCallable implements Callable<String> {
private String username;
private Long sleepTime;
public FutureCallable(String username,Long sleepTime){
super();
this.username=username;
this.sleepTime=sleepTime;
}
@Override
public String call() throws Exception {
log.info("用户名:{}",username);
Thread.sleep(sleepTime);
return username;
}
}
运行类执行代码如下:
@Slf4j
public class FutureRun {
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
FutureCallable g1 = new FutureCallable("G1", 5000L);
FutureCallable g2 = new FutureCallable("G2", 4000L);
FutureCallable g3 = new FutureCallable("G3", 3000L);
FutureCallable g4 = new FutureCallable("G4", 2000L);
FutureCallable g5 = new FutureCallable("G5", 1000L);
ArrayList<Callable> callableArrayList = new ArrayList<>();
callableArrayList.add(g1);
callableArrayList.add(g2);
callableArrayList.add(g3);
callableArrayList.add(g4);
callableArrayList.add(g5);
ArrayList<Future> futureArrayList = new ArrayList<>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
//使用CompletionService
ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(threadPoolExecutor);
for (int i = 0; i < 5 ; i++) {
executorCompletionService.submit(callableArrayList.get(i));
}
for (int i = 0; i < 5 ; i++) {
try {
log.info("等待输出第{}个返回值:{}",i+1,executorCompletionService.take().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
[pool-1-thread-2] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G2
[pool-1-thread-1] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G1
[pool-1-thread-4] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G4
[pool-1-thread-3] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G3
[pool-1-thread-5] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G5
[main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 等待输出第1个返回值:G5
[main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 等待输出第2个返回值:G4
[main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 等待输出第3个返回值:G3
[main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 等待输出第4个返回值:G2
[main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 等待输出第5个返回值:G1
从运行结果看出CompletionService完全解决了Future阻塞的特性,简单就是使用CompletionService接口后,哪个任务先执行完,哪个任务的返回值就先输出。但是在CompletionService接口中如果当前没有任务被执行完,那么CompletionService.take().get()也是会阻塞特性。