我有一个网络应用程序,需要非常快。但为了进行处理,它需要访问多个数据源。因此,我认为进行并行调用以进行优化可能会很有用。
基本上我想并行进行许多不同的数据库调用。您能给我推荐一些简单可靠的方法和技术来实现我的目标吗?如果您能提供一些框架和设计模式,那就太好了。
现在我正在使用Spring。
最佳答案
您可以使用新的Java 8 CompletableFuture
。它允许使用异步现有的同步方法。
假设您有一个格式为 List<DBRequest> listRequest
的请求列表您想要并行运行。您可以通过以下方式创建一个流并异步启动所有请求。
List<CompletableFuture<DBResult>> listFutureResult =
listRequest.stream()
.map(req -> CompletableFuture.supplyAsync(
() -> dbLaunchRequest(req), executor))
.collect(Collectors.toList());
List<DBResult> listResult =
listFutureResult.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
为了有效,您必须编写自己的自定义 Executor
private final Executor executor =
Executors.newFixedThreadPool(Math.min(listRequest.size(), 100),
new ThreadFactory(){
public Thread newThread(Runnable r){
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
});
像这样,你可以有足够的线程,但不能太多。将线程标记为守护进程可以让您即使一个线程被阻塞也能完成程序。
您可以在本书的第 11 章 Java 8 in action 中找到有关这些技术的清晰解释。
== Java 7 更新 ==
如果您坚持使用 Java 7,可以使用以下解决方案:
class DBResult{}
class DBRequest implements Callable<DBResult>{
@Override
public DBResult call(){return new DBResult();}
}
class AsyncTest{
public void test(){
try {
for(Future<DBResult> futureResult : ((ExecutorService)executor).invokeAll(listRequest)){
futureResult.get();
}
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(SoTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
所有请求都是异步运行的,然后您按照列表的顺序等待它们完成。
最后,要回答评论中的辅助问题,您不必为每个请求创建线程池。
关于Java并行数据库调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29394918/