Как я могу выполнить много вызовов WS в отдельных потоках и увеличить одну переменную результата?

#java #multithreading #struts #struts-1

#java #многопоточность #struts #struts-1

Вопрос:

Начинающий поток здесь.

Мне нужно в действии Struts извлекать некоторые данные, вызывая веб-сервис много раз с разными запросами каждый раз и ожидая завершения каждого запроса, чтобы я мог отобразить результат.

Итак, в основном я делаю это так :

 // The list of the region codes used for the requests
List<String> codesRegions;

// Init of a variable containing the total amount of data
Integer totalAmount = 0; 

// For every region
for(String codeRegion : codesRegions)
{
    MyRegionStub stub = createRegionStub();

    // Call of the WS with the code region
    MyRegionRequest request = new MyRegionRequest();
    request.setCodeRegion(codeRegion);

    // Getting the number associated to the region and incrementing totalAmount
    MyRegionResponse response = stub.getRegionStats(request);
    totalAmount  = response.getRegionStats();
}

// Once all the calls are done, I display the result
request.setAttribute("totalAmount", totalAmount);
mapping.findForward("success");
  

Моя проблема в том, что я часто получаю ошибки тайм-аута, делая это, поскольку я вызываю этот WS много раз. Итак, я хочу знать, как я могу выполнять каждый вызов в отдельном потоке и увеличивать ту же переменную результата без каких-либо ошибок.

Еще одна вещь, которую я хочу знать, мне нужно дождаться завершения всех вызовов для отображения данных. Что мне нужно сделать, чтобы вызывать mapping.findForward("success"); только тогда, когда это будет завершено?

Ответ №1:

Если вы используете java 8, я бы рекомендовал CompletableFuture

Это позволит вам создать загрузку потоков, которые выполняются асинхронно, примерно так

  CompleteableFuture<Integer> future CompleteableFuture.supplyAsync(getRegionStats(codeRegion))
  

После того, как вы создали все фьючерсы, вы можете проверить, когда все они будут завершены.

  CompleteableFuture.allOf(future1, future2).join();
  

Затем для каждого из ваших фьючерсов вы можете суммировать значения

  for(CompleteableFuture future : futures)
      totalAmount = future.get()
  

Комментарии:

1. Большое вам спасибо за ваш ответ. К сожалению, я работаю над старым проектом, используя более старую версию Java (Java 6), поэтому я не могу использовать это решение… Я буду иметь это в виду для последующих целей!

Ответ №2:

Для этого вы можете использовать Executor framework with CountDownLatch . ExecutorService будет выполнять асинхронные задачи в пуле потоков и CountDownLatch будет ждать завершения всех задач.

В этом случае вы должны отметить, что countDownLatch.countDown(); должно присутствовать в finally блоке, чтобы оно гарантированно выполнялось, и для общей суммы вы должны использовать потокобезопасный AtomicInteger .

Ваш код будет выглядеть следующим образом:

 ExecutorService threadPool = Executors.newFixedThreadPool(10);
CountDownLatch countDownLatch = new CountDownLatch(codesRegions.size());
AtomicInteger totalAmount = new AtomicInteger(0);

for (String codeRegion : codesRegions)
{
    threadPool.execute(new Runnable() {

        @Override
        public void run()
        {
            try
            {
                MyRegionStub stub = createRegionStub();

                // Call of the WS with the code region
                MyRegionRequest request = new MyRegionRequest();
                request.setCodeRegion(codeRegion);

                // Getting the number associated to the region and
                // incrementing
                // totalAmount
                MyRegionResponse response = stub.getRegionStats(request);
                totalAmount.addAndGet(response.getRegionStats());
            }
            finally
            {
                countDownLatch.countDown();
            }
        }
    });
}
try
{
    countDownLatch.await();
}
catch (InterruptedException e)
{
    //Return ERROR in case of current thread is interrupted.
}
// Once all the calls are done, I display the result
request.setAttribute("totalAmount", totalAmount);
mapping.findForward("success");