Spring boot выполняет 2 метода одновременно

У меня есть контроллер весенней загрузки, который при почтовом запросе выполняет 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";
    }
Я что-то пробовал использовать потоки, но ничего не вышло :( так ты ошибся
Antoniossss 26.09.2018 21:19
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
959
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если вы сделаете свои методы 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 к обоим методам и все? Или мне все же нужно добавить асинхронную аннотацию для каждого метода внутри реализации?

Truica Sorin 26.09.2018 21:20

Зависит от реализации. Если вы не используете @Async, вам придется отправить инвойс в пул потоков. Но так как вы можете сделать это с аннотацией ..... И помните, что вы должны вернуть AsycnResult как Future

Antoniossss 26.09.2018 21:22

Вы можете использовать службу исполнителя для отправки потоков, а затем дождаться их возврата, прежде чем продолжить:

@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

Truica Sorin 26.09.2018 21:35

Другие вопросы по теме