携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情
Future缺点
线程执行代码如下:
@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>());
for (int i = 0; i < 5 ; i++) {
futureArrayList.add(threadPoolExecutor.submit(callableArrayList.get(i)));
}
log.info("执行时间:{}",System.currentTimeMillis());
for (int i = 0; i < 5; i++) {
try {
log.info("线程执行返回值:{},执行时间:{}",futureArrayList.get(i).get(),System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
17:54:39.330 [pool-1-thread-2] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G2
17:54:39.330 [pool-1-thread-1] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G1
17:54:39.331 [pool-1-thread-5] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G5
17:54:39.330 [pool-1-thread-4] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G4
17:54:39.330 [pool-1-thread-3] INFO com.ozx.concurrentprogram.executor.service.FutureCallable - 用户名:G3
17:54:39.330 [main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 执行时间:1659952479323
17:54:44.349 [main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 线程执行返回值:G1,执行时间:1659952484349
17:54:44.350 [main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 线程执行返回值:G2,执行时间:1659952484350
17:54:44.350 [main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 线程执行返回值:G3,执行时间:1659952484350
17:54:44.351 [main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 线程执行返回值:G4,执行时间:1659952484351
17:54:44.351 [main] INFO com.ozx.concurrentprogram.executor.controller.FutureRun - 线程执行返回值:G5,执行时间:1659952484351
从运行结果看出Future接口的缺点,根据这个情况,jdk1.5版本后提供了CompletionService接口可以解决这个问题。
CompletionService使用
接口CompletionService的功能是以异步的方式一边生产新的任务,一边处理已完成任务,一边处理已完成任务的结果,这样可以将执行任务与处理任务分离开来进行处理,使用submit执行任务,使用take取得已完成的任务,并按照完成任务的时间顺序处理它们的结果。
查看CompletionService结构能看出,只有一个实现类ExecutorCompletionService,从它的构造方法的声明中可以发现,类ExecutorCompletionService需要依赖于Executor对象,大部分的实现是使用线程池ThreadExecutor对象。