#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");