Как я могу сделать много вызовов 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");