The Concurrency API introduced in Java 5 provides a latch – CountDownLatch
. A latch is a synchronizer which acts like a gate. CountDownLatch
acts like a one-time closed gate which is initially closed and can be opened only once. Once it is opened it will remain open.
In a multi-threaded application, a thread may need to wait until a set of threads have completed some execution. Usually, wait()
and notify()
methods are used when one thread has to wait until some other thread has performed some execution. When the other thread calls notify()
on the same object, the thread which went first in the WAITING
state can be granted monitor lock by the thread scheduler for execution. In case there are many waiting threads, the notifyAll()
will cause all the waiting threads to come out of the WAITING
state. However, these wait()
and notify()
or notifyAll()
calls need to be made within the synchronized block or method on the same object.
When multiple threads are running and we want to wait until all the threads have reached a certain point of execution and then perform some task, programming such a logic using wait-notifyAll or Condition
can be quite complex. We may need to use a counter to keep track of how many threads have reached that execution point or are yet to reach and may need to check this counter before calling notifyAll
. A cleaner solution to implement this logic is to use CountDownLatch
.
A CountDownLatch
constructor takes an int argument. It is usually the count of threads. The countDown()
method of this class decrements the count by 1. The thread which calls the await()
method of this class goes into the WAITING
state and will keep waiting until the count has reached zero or some other thread interrupts it. The current count can be obtained by calling the getCount()
method of this class. A timed await()
method also exists in this class which waits until the timeout has elapsed or the waiting thread is interrupted by some other thread or the latch count has reached zero. This method can be used to avoid the threads to keep waiting for long time. Since await()
is a blocking method, the checked exception InterruptedException
needs to be handled.
The CountDownLatch
acts like a latch or gate which is opened when the count reaches zero. The count in CountDownLatch
cannot be reset after its instance is created. When the count reaches zero, the await()
method will no longer make the threads go in WAITING
state. Thus, the CountDownLatch
is a one-shot latch.
The set of threads which should wait until a certain point of execution is reached, share the CountDownLatch
instance. Unlike wait-notify methods, synchronized block/method is not required to use CountDownLatch
. The CountDownLatch
is also thread-safe.
Listing 1 given below demonstrates the use of CountDownLatch
. The RandomNumberGenerator
class is an implementation of Runnable which prints 10 random numbers. The main thread creates a CountDownLatch
instance with count 5. This instance is shared amongst the RandomNumberGenerator
instances. The main thread creates a fixed size thread pool of maximum 5 threads, generates RandomNumberGenerator
instances and submits them to the ExecutorService
. The ExecutorService
dispatches a thread from the thread pool to executes the run()
method. After the Runnable
tasks are submitted, we want the main thread to wait until the execution of all threads is over. Hence, the await()
method is called on the CountDownLatch
. Since, this is called by the main thread, it will keep waiting until the count in CountDownLatch
instance reaches zero. Once the thread executing RandomNumberGenerator
has printed 10 random numbers on the console, the countDown()
method is called on the CountDownLatch
which means that one thread has completed executing its task. Thus, when the count in CountDownLatch
reaches zero, the main thread can start executing the next statements after await()
call.
public class RandomNumberGenerator implements Runnable {
private Random random = new Random();
private CountDownLatch latch;
public void setLatch(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
for(int i=1; i <= 10; i++) {
System.out.println(random.nextInt());
}
latch.countDown();
}
}
public class CountDownLatchDemo {
public static void main(String args[])
throws InterruptedException {
final int COUNT = 5;
CountDownLatch latch = new CountDownLatch(COUNT);
ExecutorService service =
Executors.newFixedThreadPool(COUNT);
System.out.println(
"printing random numbers started...");
for(int i=1; i <= COUNT; i++) {
RandomNumberGenerator generator =
new RandomNumberGenerator();
generator.setLatch(latch);
service.submit(generator);
}
latch.await();
System.out.println(
"printing random numbers stopped...";);
}
}
Listing 1. A progam using CountDownLatch
ExecutorService.awaitTermination()
The awaitTermination()
method of ExecutorService
can be called to put the thread executing this method in TIMED_WAITING
state until all the threads complete execution after shutdown()
is called or the specified timeout period in the method is over or some other thread interrupts the waiting thread.
The difference between calling awaitTermination()
on ExecutorService
and using the CountDownLatch
as given in Listing 1 is that the awaitTermination()
can be called only after shutdown()
is called. ExecutorService
cannot except new tasks for execution after shutdown()
is called. Whereas with the use of CountDownLatch
as shown in Listing 1, new tasks can be submitted to the ExecutorService
after latch.await()
is called.