How to use java.util.concurrent.CountDownLatch

With some applications that use several threads there are situations where one thread can only start after some others have completed.
For example, image a program that downloads a bunch of web pages, zips them and send then the zip file via email. If you program this in a multithreaded way, the thread that zips the downloaded web pages cannot start before the downloads are complete.
How do you do this? One very simple way is to use a CountDownLatch from the java.util.concurrent package ( a package every Java developer should have a closer look at).

With a CountDownLatch you can specify a number and then count down by 1 once an operation has completed. If all operations have completed and the count is 0, another thread that uses the same CountDownLatch as a synchronisation tool using the await method can do it’s work.

Let’s look at a simple example. The first class is a simple Runnabe that does some work. In our example it does nothing really useful, it just sleeps for a random number of milliseconds to simulate some work.

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class Worker implements Runnable {

    private CountDownLatch countDownLatch;

    public Worker(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;

    public void run() {
        try {
            Thread.sleep(getRandomSeconds()); // sleep random time to simulate long running task
            System.out.println(Counting down:  + Thread.currentThread().getName());
        } catch (InterruptedException ex) {

    // returns a long between 0 and 9999
    private long getRandomSeconds() {
        Random generator = new Random();
        return Math.abs(generator.nextLong() % 10000);

The only really interesting line here is the call to:
Once the task is done, the counter in the CountDownLatch is decremented by one.

Here is the 2nd class that uses this Runnable

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class WorkManager {

    private CountDownLatch countDownLatch;
    private static final int NUMBER_OF_TASKS = 5;

    public WorkManager() {
        countDownLatch = new CountDownLatch(NUMBER_OF_TASKS);

    public void finishWork() {
        try {
            System.out.println(START WAITING);
            System.out.println(DONE WAITING);
        } catch (InterruptedException ex) {

    public void startWork() {
        ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_TASKS);

        for (int i = 0; i < NUMBER_OF_TASKS; i++) {
            Worker worker = new Worker(countDownLatch);

    public static void main(String[] args) {
        WorkManager workManager = new WorkManager();
        System.out.println(START WORK);
        System.out.println(WORK STARTED);
        System.out.println(FINISHED WORK);

The startWork method uses and ExecutorService (another useful and important class from java.util.concurrent) to start the Runnables.
In the method finishWork we call the await method that waits until the counter inside the CountDownLatch is 0.

If you run this example you get the following output:

Counting down: pool-1-thread-3
Counting down: pool-1-thread-4
Counting down: pool-1-thread-1
Counting down: pool-1-thread-5
Counting down: pool-1-thread-2

As you can see, 5 different threads are started and the finishWork method does not complete it’s work until the
CountDownLatch is at 0.

As you can see, using a CountDownLatch is very easy. There are other similar classes in the java.util.concurrent like a CyclicBarrier which is worth looking at. In upcoming posts, I will write more about the java.util.concurrent package ant it’s useful classes, interfaces and methods.
Instead of the ExecutorService you can just use java.lang.Thread but I recommend always using the higher level ExecutorService whenever possible. With all the stuff in java.util.concurrent, there is rarely a need to use the low level classes like java.lang.Thread (which does not mean you shouldn’t know how they work!).