我有一个在 Tomcat 容器内运行的简单 Web 服务,它本质上是多线程的。在进入服务的每个请求中,我想对外部服务进行并发调用。java.util.concurrent 中的 ExecutorCompletionService 让我部分获得了成功。我可以为它提供一个线程池,它会负责执行我的并发调用,并且当任何结果准备好时我会收到通知。
处理特定传入请求的代码可能如下所示:
void handleRequest(Integer[] input) {
// Submit tasks
CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(Executors.newCachedThreadPool());
for (final Integer i : input) {
completionService.submit(new Callable<Integer>() {
public Integer call() {
return -1 * i;
}
});
}
// Do other stuff...
// Get task results
try {
for (int i = 0; i < input.size; i++) {
Future<Integer> future = completionService.take();
Integer result = future.get();
// Do something with the result...
}
} catch (Exception e) {
// Handle exception
}
}
这应该可以正常工作,但效率很低,因为正在为每个传入的请求分配一个新的线程池。如果我将 CompletionService 作为共享实例移出,我将遇到多个请求共享同一个 CompletionService 和线程池的线程安全问题。当请求提交任务并获得结果时,他们得到的结果并不是他们提交的结果。
因此,我需要的是一个线程安全的 CompletionService,它允许我在所有传入请求之间共享一个公共线程池。当每个线程完成一项任务时,应通知传入请求的相应线程,以便它可以收集结果。
实现这种功能最直接的方法是什么?我确信这种模式已经应用了很多次;我只是不确定这是否是 Java 并发库提供的东西,或者是否可以使用一些 Java 并发构建块轻松构建。
更新:我忘记提及的一个警告是,我希望在我提交的任何任务完成后立即收到通知。这是使用 CompletionService 的主要优势,因为它将任务和结果的生产和消费分离。我实际上并不关心我得到结果的顺序,我想避免在等待结果按顺序返回时不必要的阻塞。