Suppose you have 5 threads out of which 1 is a main thread and other 4 are threads that perform some task.
Now you want the main thread to proceed further only after all the 4 worker threads have finished execution.
Example,
When a laptop is started, many tasks are performed such as initialization of network service, graphic interface, input output drivers, pre-configured startup services etc.
When all these have signaled successful startup, then the login screen is displayed. Consider each of these services as a separate thread and login screen display thread as a thread waiting for these threads to complete.
This thread should proceed only when all the service threads have completed their initialization.
With traditional java thread implementation, you can do this using wait
and notifyAll
methods. But java also provides a simpler method to accomplish this by using a CountdownLatch
.
Read this to know more about java threads.
What is CountDownLatch
CountDownLatch
is used to make a thread wait till other threads finish their execution.
When all the threads finish and signal their completion, then the thread which is waiting resumes its execution. CountDownLatch
was added in java 1.5.
How to use CountDownLatch in java
A CountDownLatch
in java is implemented through a java.util.concurrent.CountDownLatch
class. When an object of this class is created, we supply the number of threads for which a thread will wait to finish execution.
This is known as the count of CountDownLatch
and it is the value of this count that decides the resumption of waiting thread.
A thread waiting for the execution will resume only when the count becomes 0.
Usage of CountDownLatch
is based on below two methods:
await()
When this method is called on an object of CountDownLatch
, the current thread pauses execution and goes into waiting state.
The thread keeps on waiting till the count of CountDownLatch
becomes zero.
This method should be called inside the thread which needs to wait for the other threads to complete.
countDown()
This method should be called from inside the worker threads. Each time this method is called, the value of count of CountDownLatch
reduces by 1.
Thus, the concept of CountDownLatch
can be summarized in below steps.
- A
CountDownLatch
is initialized with a count which is the number of child threads for which the main thread will wait before executing further.
It is an integer. - Thread which starts other threads and which wants to wait for these threads to finish calls
await
. - Every child thread when finishes execution, calls
countDown
method.
This reduces the count by 1. - When all the child threads have completed(and have called
countDown
), the value of count becomes 0 and main thread resumes its execution.
CountDownLatch
can also be considered as the number of times for which countDown()
method should be invoked on the latch so that the waiting thread can resume.Remember that both await
and countDown
should be called on the same object of CountDownLatch
. Thus, you need to share the object of CountDownLatch
among parent and child threads.
CountDownLatch example
Below is a simple example of a CountDownLatch
. It consists of a class Task
that implements java.lang.Runnable
and represents a task that thread needs to perform.
Task of a thread is written inside the overridden run
method of java.lang.Runnable
interface.
Learn about overriding methods in java here.
This class also accepts an object of java.util.concurrent.CountDownLatch
and calls its countDown
method once it finishes.
Task.java
class Task implements Runnable { CountDownLatch latch; /** * Constructor * @param l */ public Task(CountDownLatch l) { this.latch = l; } @Override public void run() { try { System.out.println("Started: " + Thread. currentThread(). getName()); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Finished: " + Thread. currentThread(). getName()); // reduce count of latch latch.countDown(); } }
Below is a main class that creates an object of java.util.concurrent.CountDownLatch
with a count of 3. It then creates an object of Task
class and supplies the same object to three threads that it creates.
After starting all the three threads, it waits for their execution to complete by calling await on the object of CountDownLatch
.
This thread will resume execution when all the threads will call countDown()
method on the latch.
Note that the object of the CountDownLatch
on which it calls await
is also shared with all the three threads for which it is waiting.
Each time a thread calls countDown()
method, count reduces by 1.
Thus, when all the threads call countDown()
, the count reaches 0 and the main thread then continues execution.
MainThread.java
public class MainThread { public static void main(String[] args) throws InterruptedException { // create an object of countdownlatch with a count of 3 CountDownLatch latch = new CountDownLatch(3); // create a task Task obj = new Task(latch); // create three worker threads Thread t1 = new Thread(obj); Thread t2 = new Thread(obj); Thread t3 = new Thread(obj); // start threads t1.start(); t2.start(); t3.start(); // current thread will wait for the worker threads to complete latch.await(); System.out.println("All Threads completed!!!"); } }
Following is the output
Started: Thread-1
Started: Thread-0
Started: Thread-2
Finished: Thread-1
Finished: Thread-2
Finished: Thread-0
All Threads completed!!!
With CountDownLatch
in place, the last line will always be printed when all the three threads have finished. Remove the statement latch.await
and notice the difference.
Let’s tweak in
- count is set when a
CountDownLatch
is created. Once initialized, count cannot be reset. - The thread in which
await
is called will keep on waiting infinitely till the count becomes zero. - If the count is greater than the number of threads, then main thread will be stuck forever.
- In case you are not sure if a child thread will call
countDown
using the overloadedawait
method which takes a timeout value so that the main thread will resume after the specified time and your application will not be stuck forever. - For getting the current count value, call
getCount
method on the object ofCountDownLatch
. - Nothing will happen if
countDown()
method is called and the count is 0.