I have an application where for a certain number of times something needs to be calculated. This calculation function has the annotation @Async (from the Spring Framework), that
If you need to wait for the executions to finish, then you can return a Future
as a return value, e.g.
@Async
public Future<Void> executeBla() {
System.out.println("Bla!");
return new AsyncResult<Void>(null);
}
This is slightly artificial, since there's no actual value being returned, but it will still allow the calling code to wait for all executions to finish:
public void executeBlaALotOfTimes() {
long before = System.currentTimeMillis();
Collection<Future<Void>> futures = new ArrayList<Future<Void>>();
for (int i = 0; i<40000; i++) {
futures.add(executeBla());
}
for (Future<Void> future : futures) {
future.get();
}
long after = System.currentTimeMillis();
System.out.println("Time it took for a lot of bla to execute: " + (after - before) / 1000.0 + " seconds.");
}
Here, the first loop fires off the async tasks and stores the futures in a list. The seconds loop then iterates over the futures, waiting for each one to finish.
An alternative is to return a ListenableFuture
and to use a CountDownLatch
.
@Async
public ListenableFuture<Void> executeBla() {
try {
System.out.println("Bla!");
return AsyncResult.forValue(null);
} catch (Throwable t) {
return AsyncResult.forExecutionException(t);
}
}
This scenario allows you to avoid explicitly calling future.get()
for each future. You accomplish this by adding success and failure callbacks which in turn decrement the CountDownLatch
, which was created exactly for this purpose.
public void executeBlaALotOfTimes() {
long before = System.currentTimeMillis();
int numExecutions = 40000;
CountDownLatch countDownLatch = new CountDownLatch(numExecutions);
for (int i = 0; i<numExecutions; i++) {
ListenableFuture<Void> future = executeBla();
future.addCallback(
aVoid -> countDownLatch.countDown(),
throwable -> countDownLatch.countDown()
);
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
// Handle exception
} finally {
long after = System.currentTimeMillis();
System.out.println("Time it took for a lot of bla to execute: " + (after - before) / 1000.0 + " seconds.");
}
}