invokeAll和CompletionService
需求场景:服务A依赖于其他三个服务:服务B、服务C、服务D,而服务A的调用方要求服务A在100ms内返回结果。服务A需要在100ms内把已经有结果的服务返回,取消无结果的服务。
使用ExecutorService.invokeAll()方法,该方法输入是一个Callable任务的集合,返回的是Future集合,Future集合的顺序与输入的任务一样。invokeAll()的超时时限是对这一整组集合来说的。
该方法会阻塞,当所有任务执行完毕或者超时的时候,方法就会返回,若有未完成的任务,invokeAll()方法中会调用cancel(true)方法来取消任务。我们可以对返回的Future调用isCancelled()方法来看该任务是否已经执行完毕。
public void testCustomerExecutorException() {
List<SayHello> tasks = Lists.newArrayList();
for (int i = 5; i >= 1; i--) {
tasks.add(new SayHello(i));
}
List<Future<String>> futures = Lists.newArrayList();
try {
futures = fixedExecutorService.invokeAll(tasks, 250, TimeUnit.MILLISECONDS);
} catch (Exception e) {
System.out.println("Main: " + e);
}
for (Future<String> future :futures) {
try {
String s = future.get();
System.out.println("get ok: " + s);
} catch (Exception e) {
System.out.println("get error: " + e);
}
}
}
private class SayHello implements Callable<String> {
private int id;
public SayHello(int id) {
this.id = id;
}
public String call() throws Exception {
try {
Thread.sleep(id*100);
} catch (Exception e) {
System.out.println(id + "; SayHello: " + e);
return "hello " + id;
}
return "hello " + id;
}
}
CompletionService与invokeAll的不同点在于:
CompletionService:任务执行完毕马上返回
invokeAll:需要等全部任务执行完毕或者超时再返回
public ExecutorService fixedExecutorService = Executors.newFixedThreadPool(5);
private final BlockingQueue<Future<String>> queue = new LinkedBlockingDeque<Future<String>>(10);
private final CompletionService<String> completionService = new ExecutorCompletionService<String>(fixedExecutorService, queue);
public void testCustomerExecutorException() {
for (int i = 5; i >= 1; i--) {
completionService.submit(new SayHello(i));
}
for (int i = 0; i < 5; i++)
{
try {
//谁最先执行完成,直接返回
Future<String> f = completionService.take();
System.out.println(f.get());
} catch (Exception e) {
}
}
}
private class SayHello implements Callable<String> {
private int id;
public SayHello(int id) {
this.id = id;
}
public String call() throws Exception {
try {
Thread.sleep(id*100);
} catch (Exception e) {
return "hello " + id;
}
return "hello " + id;
}
}
//输出
//hello1
//hello2
//hello3
//hello4
//hello5