Learnitweb

CountDownLatch in Java

1. Introduction

The Java concurrency API provides a CountDownLatch class that allows one or more threads to wait until a set of operations are done.

CountDownLatch is initialized with an integer value (N). This count is the number of operations the threads are going to wait for. When a thread wants to wait for the execution of these operations, it calls await() method. This method causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted. When one of these operations completes, it uses the countDown() method to decrement the internal counter of the CountDownLatch. When the counter reaches to 0, the class wakes up all the threads that were sleeping in the await() method.

The CountDownLatch class has three basic elements:

  • The initialization value that determines how many operations one thread has to wait for other threads to complete.
  • The await() method causes the current thread to wait until the latch has counted down to zero.
  • The countDown() method decrements the count of the latch, releasing all waiting threads if the count reaches zero.

The typical usage of CountDownLatch is like the following:

  1. main thread is created.
  2. main thread creates a CountDownLatch with some initial value.
  3. main thread creates and starts other application threads.
  4. main thread calls await().
  5. Application thread runs and calls countDown() method to reduce the count by 1.
  6. The count reaches 0 and the main thread passes through await().

There’s no way to re-initialize the internal counter of the CountDownLatch object or to modify its value. Once the counter is initialized, the only method you can use to modify its value is the countDown() method. If you have any such requirement, you should use CyclicBarrier class.

A typical use of CountDownLatch is to divide a problem in N parts. Each smaller part of the problem will be solved with a Runnable which will count down on the latch. When all parts of the problem are solved, the coordinating thread will be able to pass through await().

A CountDownLatch initialized with a count of one serves as a simple on/off gate. In this case all threads invoking await() wait at the gate until a thread opens the gate by invoking countDown().

The main purpose of CountDownLatch latch is not to protect a shared resource. CountDownLatch enables the main thread to wait until other threads are finished. Configuring how many number of threads a main thread should wait is very easily and is done by setting a count.

2. Example of CountDownLatch

In this example, we’ll create a CountDownLatch initialized with value of 4. We’ll then create 4 threads. The main thread will start these threads and will call await() on CountDownLatch instance. The main thread will not pass through the gate until the count reaches 0. Each thread once done with the processing will reduce the count by 1. Once the count reaches 0, the main thread will pass through await().

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
	public static void main(String args[]) {
		CountDownLatch countDownLatch = new CountDownLatch(4);

		Thread application1 = new Thread(new Application("Application1", countDownLatch));
		Thread application2 = new Thread(new Application("Application2", countDownLatch));
		Thread application3 = new Thread(new Application("Application3", countDownLatch));
		Thread application4 = new Thread(new Application("Application4", countDownLatch));

		// start threads
		application1.start();
		application2.start();
		application3.start();
		application4.start();

		try {
			// wait until countDownLatch reduces to 0.
			countDownLatch.await();

			System.out.println("All applications started.");
		} catch (InterruptedException e) {
			System.out.println(e.getMessage());
		}
	}
}

class Application implements Runnable {
	private String name;
	private CountDownLatch countDownLatch;

	public Application(String name, CountDownLatch countDownLatch) {
		this.name = name;
		this.countDownLatch = countDownLatch;
	}

	public void run() {
		try {
			System.out.println(name + " started and processing.");
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			System.out.println(e.getMessage());
		}
		System.out.println(name + " processing done.");

		// reduce the count of latch by 1
		countDownLatch.countDown();
	}
}

Output

Application2 started and processing.
Application4 started and processing.
Application3 started and processing.
Application1 started and processing.
Application3 processing done.
Application4 processing done.
Application1 processing done.
Application2 processing done.
All applications started.