Future 有一个问题就是,他的get 方法是把全部数据处理完再拿出来的。
ExecutorCompletionService 可以做到拿一条输出一条
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
final List<Callable<Integer>> callableList = Arrays.asList(
() -> {
sleep(10);
System.out.println("sleep 10 seconds");
return 10;
},
() -> {
sleep(20);
System.out.println("sleep 10 seconds");
return 20;
}
);
ExecutorCompletionService<Integer> completionService = new ExecutorCompletionService(executorService);
List<Future<Integer>> futures = new ArrayList<>();
callableList.stream().forEach(callable -> futures.add(completionService.submit(callable)));
Future<Integer> future;
//take 会阻塞
// poll 方法不是阻塞方法,拿的时候会出现空指针
while((future = completionService.take()) != null){
System.out.println(future.get());
}
}
public static void sleep(int time){
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
场景应用
在实际开发的时候,会在一定时间内处理一些问题,但是没处理的问题,也需要保留起来
ExecutorCompletionService 关注的是已经完成的东西
public static void main(String[] args) throws ExecutionException, InterruptedException {
// ExecutorCompletionService 关注得是已完成得
// 如果shutdownNow 方法调用,我是没办法知道
/*ExecutorService service = Executors.newSingleThreadExecutor();
List<Runnable> task = IntStream.range(0, 5).boxed().map(ScheduleExecutorServiceTest::toTask).collect(Collectors.toList());
ExecutorCompletionService<Object> completionService = new ExecutorCompletionService<>(service);
task.forEach(r -> completionService.submit(Executors.callable(r)));
TimeUnit.SECONDS.sleep(13);
List<Runnable> runnables = service.shutdownNow();
System.out.println(runnables);*/
// 以下方式自定义能拿到所有未完成得
ExecutorService service = Executors.newSingleThreadExecutor();
List<Callable> task = IntStream.range(0, 5).boxed().map(MyTask::new).collect(Collectors.toList());
ExecutorCompletionService<Integer> completionService = new ExecutorCompletionService<>(service);
task.forEach(completionService::submit);
TimeUnit.SECONDS.sleep(13);
service.shutdownNow();
// System.out.println(runnables);
task.stream().filter(callable -> !((MyTask)callable).isSuccess()).forEach(System.out::println);
}
private static class MyTask implements Callable<Integer>{
private final Integer value;
private boolean success = false;
private MyTask(Integer value) {
this.value = value;
}
@Override
public Integer call() throws Exception {
System.out.println("the task will be executed" + value);
TimeUnit.SECONDS.sleep(value * 5 + 5);
System.out.println("the task executed done" + value);
success = true;
return value;
}
public boolean isSuccess() {
return success;
}
}
private static Runnable toTask(int i){
return () -> {
try {
System.out.println("the task will be executed" + i);
TimeUnit.SECONDS.sleep(i * 5 + 5);
System.out.println("the task executed done" + i);
} catch (InterruptedException e) {
System.out.println("the task be interrupted" + i); }
};
}