使用CompletionService解决耗时时间过长任务导致的阻塞问题
package com.dwz.executors; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * 有5个任务,其中4个任务执行速度很快,另1个耗时过长,我们不想等待耗时过长的任务执行完成而想立刻拿到4个执行时间较短任务的结果 */ public class ComplexExample { private static Runnable toTask(int i) { return () -> { try { System.out.printf("The task [%d] will be executed. ", i); TimeUnit.SECONDS.sleep(i*5 + 10); System.out.printf("The task [%d] executed done. ", i); } catch (InterruptedException e) { System.out.printf("The task [%d] be interrupted. ", i); } }; } private static void test1() throws InterruptedException, ExecutionException { final ExecutorService service = Executors.newFixedThreadPool(5); List<Runnable> tasks = IntStream.range(0, 5).boxed().map(ComplexExample::toTask).collect(Collectors.toList()); List<Future<?>> futureList = new ArrayList<>(); tasks.forEach(r -> { futureList.add(service.submit(r)); }); futureList.get(4).get(); System.out.println("==========4========="); futureList.get(3).get(); System.out.println("==========3========="); futureList.get(2).get(); System.out.println("==========2========="); futureList.get(1).get(); System.out.println("==========1========="); futureList.get(0).get(); System.out.println("==========0========="); } private static void test2() throws InterruptedException, ExecutionException { final ExecutorService service = Executors.newFixedThreadPool(5); List<Runnable> tasks = IntStream.range(0, 5).boxed().map(ComplexExample::toTask).collect(Collectors.toList()); final CompletionService<Object> completionService = new ExecutorCompletionService<>(service); tasks.forEach(r -> { completionService.submit(Executors.callable(r)); }); Future<?> future; while((future = completionService.take()) != null) { System.out.println(future.get()); } } }
解决ExecutorService.shutdownNow()导致正在执行中的任务被打断,但该任务不会被返回问题
package com.dwz.executors; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * 有5个任务,其中4个任务执行速度很快,另1个耗时过长,我们不想等待耗时过长的任务执行完成而想立刻拿到4个执行时间较短任务的结果 */ public class ComplexExample { //出现执行shutdownNow()之后正在执行中的任务被打断,但该任务不会被返回 private static void test3() throws InterruptedException, ExecutionException { final ExecutorService service = Executors.newSingleThreadExecutor(); List<Runnable> tasks = IntStream.range(0, 5).boxed().map(ComplexExample::toTask).collect(Collectors.toList()); final CompletionService<Object> completionService = new ExecutorCompletionService<>(service); tasks.forEach(r -> { completionService.submit(Executors.callable(r)); }); TimeUnit.SECONDS.sleep(12); List<Runnable> runnables = service.shutdownNow(); System.out.println(runnables); } private static class MyTask implements Callable<Integer> { private final Integer value; private boolean success = false; MyTask(Integer value) { this.value = value; } public boolean isSuccess() { return success; } @Override public Integer call() throws Exception { System.out.printf("The task [%d] will be executed. ", this.value); TimeUnit.SECONDS.sleep(this.value * 5 + 10); System.out.printf("The task [%d] executed done. ", this.value); success = true; return this.value; } } //解决执行shutdownNow()之后正在执行中的任务被打断,让该任务被返回 private static void test4() throws InterruptedException, ExecutionException { final ExecutorService service = Executors.newSingleThreadExecutor(); List<Callable<Integer>> tasks = IntStream.range(0, 5).boxed().map(MyTask::new).collect(Collectors.toList()); final CompletionService<Integer> completionService = new ExecutorCompletionService<>(service); tasks.forEach(completionService::submit); TimeUnit.SECONDS.sleep(12); service.shutdownNow(); tasks.stream().filter(callable -> !((MyTask) callable).isSuccess()).forEach(System.out::println); } }