October 14, 2022

CountDownLatch in Java With Examples

CountDownLatch in Java is a synchronization aid that allows one or more threads to wait for a set of operations being performed in other threads to complete.

CountDownLatch class was added in Java 1.5 and it is part of java.util.concurrent package in Java.

How CountDownLatch works in Java

A CountDownLatch is initialized with a given count then there are two methods await() and countDown() that block and release the threads.

  1. await()- Causes the current thread to wait until the latch has counted down to zero.
  2. countDown()- Decrements the count of the latch, releasing all waiting threads if the count reaches zero.

CountDownLatch as the name itself goes can be thought of as fastening the latch so that the current thread is blocked when await method is called and waits for the countdown to reach zero from the given count. When the count reaches zero latch is opened for the thread(s) to proceed.

Java CountDownLatch constructor

CountDownLatch(int count)- Constructs a CountDownLatch initialized with the given count. Here count specifies the number of events that must happen to make the count zero by counting down after each event.

Java CountDownLatch methods

Apart from await() and countDown() method which are already showed above following are some of the other methods in the CountDownLatch class.

  • await(long timeout, TimeUnit unit)- Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted, or the specified waiting time elapses.
  • getCount()- Returns the current count.

CountDownLatch Java example

Let’s say you have a scenario where you have a set of threads performing some task but you want those thread to start only after some set up work is finished by the main thread. Once the set of threads start, main thread should wait and continue only after set of threads have finished the task. In this case you can use two countdown latches-

First CountDownLatch is used to prevent any thread from starting its operation until the main thread is finished with set up tasks.

Second CountDownLatch acts as a completion signal that makes the set of threads to wait until all threads have completed. That gives main thread a signal to proceed.

import java.util.concurrent.CountDownLatch;

public class CLDemo {
  public static void main(String[] args) {
    CountDownLatch startLatch = new CountDownLatch(1);
    CountDownLatch doneLatch = new CountDownLatch(3);
    for(int i = 0; i < 3; i++) {
      new Thread(new Worker(startLatch, doneLatch)).start();;
    }
    try {
      Thread.sleep(500);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    System.out.println("Main thread - Doing setup");
    //Signal from main thread for other threads to start
    startLatch.countDown();
    try {
      // Main thread waiting for other threads to finish
      doneLatch.await();
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    System.out.println("Main thread - Proceed after all the threads are done");
  }
}

class Worker implements Runnable{
  private final CountDownLatch startLatch;
  private final CountDownLatch doneLatch;
  Worker(CountDownLatch startLatch, CountDownLatch doneLatch) {
    this.startLatch = startLatch;
    this.doneLatch = doneLatch;
  }
  @Override
  public void run() {
    try {
      System.out.println("Calling await ...");
      // don't start until set up is done
      startLatch.await();
      System.out.println("Doing processing " + Thread.currentThread().getName());
      doneLatch.countDown();
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
Calling await ...
Calling await ...
Calling await ...
Main thread - Doing setup
Doing processing Thread-0
Doing processing Thread-2
Doing processing Thread-1
Main thread - Proceed after all the threads are done

As you can see from the output three threads are started and all three start executing run method also but blocked by the call to startLatch.await(); This ensures that the threads don’t start their processing until the main thread is done with the set up. Once the startLatch.countDown(); is called in the main thread, threads start the processing.

Now the main thread waits because of the call to doneLatch.await(); Since the doneLatch is initialized with the count of 3 so the main thread is blocked until the countDown() method is called 3 times. Once the count reaches 0 main thread proceeds with its execution.

CountDownLatch in Java is not reusable

One important point about CountDownLatch in Java is that it is not reusable like the other synchronization aid CyclicBarrier which can be reused. Once the count reaches zero it can’t be reset. Once the countdown reaches zero, call to await() method won't block any thread so ensure the synchronization between the count CountDownLatch is initialized with and how many times countDown() method is called.

In the previous example if we create 6 threads instead of 3 but let the count in doneLatch remain 3.

public class CLDemo {
  public static void main(String[] args) {
    CountDownLatch startLatch = new CountDownLatch(1);
    CountDownLatch doneLatch = new CountDownLatch(3);
    for(int i = 0; i < 6; i++) {
      new Thread(new Worker(startLatch, doneLatch)).start();;
    }
    try {
      Thread.sleep(500);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    System.out.println("Main thread - Doing setup");
    //Signal from main thread for other threads to start
    startLatch.countDown();
    try {
      // Main thread waiting for other threads to finish
      doneLatch.await();
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    System.out.println("Main thread - Proceed after all the threads are done");
  }
}

class Worker implements Runnable{
  private final CountDownLatch startLatch;
  private final CountDownLatch doneLatch;
  Worker(CountDownLatch startLatch, CountDownLatch doneLatch) {
    this.startLatch = startLatch;
    this.doneLatch = doneLatch;
  }
  @Override
  public void run() {
    try {
      System.out.println("Calling await ...");
      // don't start until set up is done
      startLatch.await();
      System.out.println("Doing processing " + Thread.currentThread().getName());
      doneLatch.countDown();
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
Calling await ...
Calling await ...
Calling await ...
Calling await ...
Calling await ...
Calling await ...
Main thread - Doing setup
Doing processing Thread-1
Doing processing Thread-4
Doing processing Thread-3
Doing processing Thread-2
Doing processing Thread-0
Main thread - Proceed after all the threads are done
Doing processing Thread-5

As you can see from the output now main thread can start processing any time once the countdown reaches zero from three.

That's all for the topic CountDownLatch in Java With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment