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

Новичок темы здесь.

Мне нужно в действии 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"); только когда это закончится?

2 ответа

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

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

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

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

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

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

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

Ты можешь использовать Executor framework с 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");
Другие вопросы по тегам