StackTips
 10 minutes

CountDownLatch and Java Concurrency Example

By Nilanchala @nilan, On Mar 05, 2024 Java 2.3K Views

CountDownLatch is one of the most useful Java concept that helps tracking multiple threads execution. This is useful when you want one or more threads to wait until a set of operations being performed in other threads completes.

CountDownLatch helps in achieving maximum parallelism between multiple threads. Lets take a case here; sometimes you want to start multiple threads at the same time in parallel to main thread and once all the threads complete, you have to perform some actions on your main thread. This can be done easily if we create a CountDownLatch.

How it works?

A CountDownLatch is initialized with a given N count. The await methods block the current thread execution until the count reaches zero. Once a task/thread completes the countDown() method will be called which results N– for every call. Once N size reaches zero, the thread which was awaiting returns immediately. CountDownLatch doesn't allow to change the count at runtime. i.e. once initialized it cannot be increased or reset.

Create CountDownLatch and initialize with the count N. Other worker threads must have reference of latch object, because they will need to notify the CountDownLatch object that they have completed their task.

This notification is done by countDown() method. Each time we call countDown() method, it decreases count of N. When all N threads have called this method, count reaches to zero and main thread is allowed to resume its execution.

CountDownLatch Example

In this example, we will download multiple images using worker thread. Once all the download complete, I expect my main thread to resume its execution. This example is a more simplified version just for your easy understanding.

First lets solve this problem without using CountDownLatch

CountDownLatchTest.java

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {
	private static int N = 6;

	public static void main(String[] args) {		
		try {
			for (int i = 0; i < N; i++) {
				new Thread(new MyWorker()).start();
			}
			
			System.out.println("*** Main Thread in Action ***");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

MyWorker.java

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.CountDownLatch;

public class MyWorker implements Runnable {

	public MyWorker() {		
	}

	@Override
	public void run() {
		try {
			URL url = new URL(
					"http://3rdbillion.net/wp-content/uploads/2013/11/35e7e6728456fed40f4f1b27d5d41c8513.jpg");
			InputStream in = new BufferedInputStream(url.openStream());
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			byte[] buf = new byte[1024];
			int n = 0;
			while (-1 != (n = in.read(buf))) {
				out.write(buf, 0, n);
			}
			out.close();
			in.close();
			byte[] response = out.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("*** Worker Thread ****");

	}
}

In the above code snippet we have used multiple threads to download an image. (In this example, the downloaded image is only for demonstration, not being used for anything). Execute the above program, you will notice that it will results the output something similar as below

Output

*** Main Thread in Action ***
*** Worker Thread ****
*** Worker Thread ****
*** Worker Thread ****
*** Worker Thread ****
*** Worker Thread ****
*** Worker Thread ****

Using CountDownLatch Example

CountDownLatchTest.java

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {

	private static CountDownLatch _latch;
	private static int N = 6;

	public static void main(String[] args) {
		_latch = new CountDownLatch(N);

		try {
			for (int i = 0; i < N; i++) {
				new Thread(new MyWorker(_latch)).start();
			}

			_latch.await();

			System.out.println("*** Main Thread in Action ***");

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

MyWorker.java

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.CountDownLatch;

public class MyWorker implements Runnable {
	private CountDownLatch _latch = null;

	public MyWorker(CountDownLatch _latch) {
		this._latch = _latch;
	}

	@Override
	public void run() {
		try {

			URL url = new URL(
					"http://3rdbillion.net/wp-content/uploads/2013/11/35e7e6728456fed40f4f1b27d5d41c8513.jpg");
			InputStream in = new BufferedInputStream(url.openStream());
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			byte[] buf = new byte[1024];
			int n = 0;
			while (-1 != (n = in.read(buf))) {
				out.write(buf, 0, n);
			}

			out.close();
			in.close();

			byte[] response = out.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}

		System.out.println("*** Worker Thread ****");

		_latch.countDown();
	}
}

Output

*** Worker Thread ****
*** Worker Thread ****
*** Worker Thread ****
*** Worker Thread ****
*** Worker Thread ****
*** Worker Thread ****
*** Main Thread in Action ***

Notice the output above, the main thread was awaiting until all other worker threads completes their execution.
If you like reading this post, please don’t forget to hit like or share with your friends!

nilan avtar

Nilanchala

I'm a blogger, educator and a full stack developer. Mainly focused on Java, Spring and Micro-service architecture. I love to learn, code, make and break things.