异步调用两个Java方法

异步调用两个Java方法,java,multithreading,asynchronous,Java,Multithreading,Asynchronous,我有以下代码调用两个web服务。两个web服务都返回非常大的响应,因此响应需要相当长的时间才能返回(一个web服务请求为8秒,另一个为12秒)。总执行时间为20秒,因为请求是串行而不是并行运行的 是否有任何方法可以修改代码以异步请求这两个web服务,并能够在比当前所需的20秒更接近12秒的时间内处理响应 String listOfCities; String listOfCountries; try { listOfCities = service.getListOfCities(h

我有以下代码调用两个web服务。两个web服务都返回非常大的响应,因此响应需要相当长的时间才能返回(一个web服务请求为8秒,另一个为12秒)。总执行时间为20秒,因为请求是串行而不是并行运行的

是否有任何方法可以修改代码以异步请求这两个web服务,并能够在比当前所需的20秒更接近12秒的时间内处理响应

String listOfCities;
String listOfCountries; 

try {
    listOfCities = service.getListOfCities(host+"service/cities");
    listOfCountries = service.getListOfCountries(host+"service/countries");
} catch (Exception e) {
    log.error("Failed to read service: " + e);
}

**感谢您的回复,我觉得这不是重复的,因为我想停止我正在执行的两个线程的执行,直到它们都收到来自这两个线程的结果。下面的解决方案表明了这一点**

类的全局变量

String listOfCities;
String listOfCountries; 
在函数中,方法的调用方式如下所示

try {//t is the object of the class like (Test t = new Test();)
    new Thread(()-> t.listOfCities = service.getListOfCities(host+"service/cities");).start();
    new Thread(()-> t.listOfCountries = service.getListOfCountries(host+"service/countries");).start();
} catch (Exception e) {
    log.error("Failed to read service: " + e);
}
代码示例


通过@AniketSahrawat

非常简单的实现,您可能需要了解更多的进展

List-threadList=new-ArrayList();
添加(新线程(newrunnable()){
@凌驾
公开募捐{
试一试{
listOfCountries=service.getListOfCountries(主机+“服务/国家”);
}捕获(例外e){
日志错误(“读取服务失败:+e”);
}
}
}));
添加(新线程(newrunnable()){
@凌驾
公开募捐{
试一试{
listOfCities=service.getListOfCities(主机+“服务/城市”);
}捕获(例外e){
日志错误(“读取服务失败:+e”);
}
}
}));
对于(线程t:线程列表){
t、 start();
}
对于(线程t:线程列表){
试一试{
t、 join();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
//完成后,从这里开始

注意字符串的定义应该更加全局(类级别,而不是局部变量)

我会尝试一些简单的方法,比如:

import java.util.concurrent.CompletableFuture;
...
final CompletableFuture listOfCities=CompletableFuture.supplyAsync(()->service.getListOfCities(…);
最终CompletableFuture国家列表=CompletableFuture.supplyAsync(()->service.getListOfCountries(…);
最终CompletableFuture allCompleted=CompletableFuture.allOf(城市列表、国家列表);
全部完成。然后运行(()->{
//你想干什么都行
});

请参阅这些以供参考。

如果您希望按照完成顺序计算执行时间,我建议您使用番石榴。我会做好的

示例用法可以如下所示:

ExecutorService es;
Callable<String> task1;
Callable<String> task2;
//...
ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(es);
List<ListenableFuture<String>> yourTasks = new ArrayList<>();
yourTasks.add(listeningExecutorService.submit(task1));
yourTasks.add(listeningExecutorService.submit(task2));
for(Future f: Futures.inCompletionOrder(yourTasks)){
   //process your task in completion order now
}
服务执行人;
可调用任务1;
可调用任务2;
//...
ListengExecutorService ListengExecutorService=MoreExecutors.ListengDecorator;
列出您的任务=新建ArrayList();
添加(ListingExecutorService.submit(task1));
添加(ListingExecutorService.submit(任务2));
for(未来f:Futures.CompletionOrder(您的任务)){
//现在按完成顺序处理任务
}

检查问题。您需要创建两个线程,每个线程启动一个服务。然后,主逻辑线程(第三个)将等待并定期检查其他两个线程是否已经完成。如果他们这样做了,你可以得到他们的结果并继续。请注意,实现这一点的方法有很多(特别是在Java8和Java9之后)。我不知道目前哪些方法被认为是最佳实践。谢谢尤达大师-我唯一的问题是,在调用这两个服务并返回响应之前,我不希望应用程序执行任何其他行。我该怎么做呢?您可以编写一个回调方法,在两个线程都完成运行时执行。检查看,因为闭包,它不会工作。@AniketSahrawat你能编辑它使它工作吗?我也是java多线程新手,非常感谢您的帮助。如果不是的话,你能提供一个很好的参考吗?我不明白为什么这个答案被提升了
listOfCities
listOfCountries
是局部变量,这种方法必须失败,因为lambda要求变量是有效的最终变量@FarhanQasim如果你是Java多线程新手,那么在回答之前你应该先学习它,顺便说一句,你回答中的错误与多线程无关,而是闭包。检查方法vs@AniketSahrawat谢谢,先生,我现在将编辑我的答案。不确定您的代码与
FutureTask
有什么关系?我的代码与FutureTask没有任何关系,但为了更高级地使用异步任务,我建议提出问题的人查看本课程,编辑我的答案以避免confusion@SarelFoyerlicht有人可能会认为你在这里使用“植入”是无意的:)“实施”字眼冗长,眼睛疲劳
import java.util.concurrent.CompletableFuture;
...
final CompletableFuture<String> listOfCities = CompletableFuture.supplyAsync(() -> service.getListOfCities(...));
final CompletableFuture<String> listOfCountries = CompletableFuture.supplyAsync(() -> service. getListOfCountries(...));
final CompletableFuture<Void> allCompleted = CompletableFuture.allOf(listOfCities, listOfCountries);
allCompleted.thenRun(() -> {
    // whatever you want to do 
});
ExecutorService es;
Callable<String> task1;
Callable<String> task2;
//...
ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(es);
List<ListenableFuture<String>> yourTasks = new ArrayList<>();
yourTasks.add(listeningExecutorService.submit(task1));
yourTasks.add(listeningExecutorService.submit(task2));
for(Future f: Futures.inCompletionOrder(yourTasks)){
   //process your task in completion order now
}