У меня есть контроллер весенней загрузки, который при почтовом запросе выполняет 2 метода, которые возвращают 2 списка, и эти 2 списка отправляются на страницу просмотра. Каждому из этих двух методов требуется около 15 секунд, поэтому контроллеру потребуется 30-40 секунд, чтобы отправить этот список на страницу. Как я смогу выполнить эти методы одновременно и сократить время? Я пробовал что-то с использованием потоков но ничего не сделал :(
@RequestMapping(path = "search", method = RequestMethod.POST)
public String searchPage(@ModelAttribute("specification") Specification specification, Model model) throws InterruptedException {
List<SearchResult1> list1;
List<SearchResult2> lista2;
list1 = service1.search(params);
list2 = service2.search(params);
model.addAttribute("list1", list1);
model.addAttribute("list2", list2);
return "home";
}




Если вы сделаете свои методы search асинхронными, используя пул исполнителей потоков или @Async, вы сможете вызывать их сразу и собирать результаты после завершения.
Только помните, что для этого вам нужно будет использовать Future.
Так будет что-то вроде этого
@Async
public Future<List<Whatever>> search(whatever here){
resultList=whateverYouDoThere();
return new AsyncResult<Whatever>(resultList);
}
как в сервисах ofc, так и в invocations:
List<Whatever> completeList=new ArrayList():
Future<Whatever> fut1=service1.search(...);
Future<Whateva> fut2=service2.search(...);
completeList.addAll(fut1.get());
completeList.addAll(fut2.get();
//here you got all the stuff in completeList
Я пропустил ваш случай здесь, так как мне было лень внимательно его читать, поэтому в вашем случае это будет
Future<SearchResult1> fut1=service1.search(params);
Future<SerchResult2> fut2 = service2.search(params);
model.addAttribute("list1", fut1.get());
model.addAttribute("list2", fut2.get());
или что-то очень похожее
Так что мне просто нужно добавить Future к обоим методам и все? Или мне все же нужно добавить асинхронную аннотацию для каждого метода внутри реализации?
Зависит от реализации. Если вы не используете @Async, вам придется отправить инвойс в пул потоков. Но так как вы можете сделать это с аннотацией ..... И помните, что вы должны вернуть AsycnResult как Future
Вы можете использовать службу исполнителя для отправки потоков, а затем дождаться их возврата, прежде чем продолжить:
@RequestMapping(path = "search", method = RequestMethod.POST)
public String searchPage(@ModelAttribute("specification") Specification specification, Model model) throws InterruptedException {
ExecutorService executor = Executors.newCachedThreadPool();
List<Callable<Map<String, List<?>>>> callables = new ArrayList<>();
Callable<Map<String, List<?>>> callable1 = new Callable<Map<String,List<?>>>() {
@Override
public Map<String, List<?>> call() throws Exception {
Map<String, List<String>> map = new HashMap<>();
map.put("list1", service1.search(params));
return map;
}
};
callables.add(callable1);
Callable<Map<String, List<?>>> callable2 = new Callable<Map<String,List<?>>>() {
@Override
public Map<String, List<?>> call() throws Exception {
Map<String, List<String>> map = new HashMap<>();
map.put("list2", service2.search(params));
return map;
}
};
callables.add(callable2);
List<Future<Map<String, List<?>>>> futures = executor.invokeAll(callables);
for (Future<Map<String, List<?>>> f : futures) {
Map<String, List<?>> results = f.get();
Entry<String, List<?>> res = results.entrySet().iterator().next();
model.addAttribute(res.getKey(), res.getValue());
}
return "home";
}
По сути, вы будете отправлять эти задачи, а звонок на future.get() будет ждать ответа. Я немного изменил его, чтобы результаты отображались на карте, где ключ - это имя списка, а значение - результаты поиска.
Спасибо за помощь! Я посмотрю, что я могу сделать с обоими ответами: D