Chapter 15. CountDownLatch—Friend or Foe?
Alexey Soshin
Let’s imagine a situation in which we’d like to launch multiple concurrent tasks, and then wait on their completion before proceeding further. The ExecutorService makes the first part easy:
ExecutorService pool = Executors.newFixedThreadPool(8);
Future<?> future = pool.submit(() -> {
// Your task here
});
But how do we wait for all of them to complete? CountDownLatch comes to our rescue. A CountDownLatch takes the number of invocations as a constructor argument. Each task then holds a reference to it, calling the countDown method when the task completes:
int tasks = 16;
CountDownLatch latch = new CountDownLatch(tasks);
for (int i = 0; i < tasks; i++) {
Future<?> future = pool.submit(() -> {
try {
// Your task here
}
finally {
latch.countDown();
}
});
}
if (!latch.await(2, TimeUnit.SECONDS)) {
// Handle timeout
}
This example code will launch 16 tasks, then wait for them to finish before proceeding further. There are some important points to take note of, though:
-
Make sure that you release the latch in a
finallyblock. Otherwise, if an exception occurs, your main thread may wait forever. -
Use the
awaitmethod that accepts a timeout period. That way, even if you forget about the first point, your thread will wake up sooner or later. -
Check the return value of the method. It returns
falseif the time has elapsed, or