What is CountDownLatch in Java ? How to use CountDownLatch ?

CountDownLatch in Java is a synchronization tool that allows one or more threads to wait until one or more number of threads completed some operation. So there are 2 types of threads,

Type 1 : One/more are waiting thread(s).
Type 2 : Threads for which the Type 1 thread(s) is/are waiting for.

Here the CountDownLatch is initialized with a count which is decremented each time a Type 2 thread completes its execution. When count reaches to zero, it means all Type 2 threads have completed their execution, and then Type 1 thread(s) waiting on latch resume the execution. CountDownLatch is introduced on Java 5 with other concurrent utilities like CyclicBarrier, Semaphore, ConcurrentHashMap and BlockingQueue in java.util.concurrent package. Now as of now we knew that Type 1 thread can be one or many. But from this point we will consider only one thread will wait for multiple threads to complete for the simplicity of an example.

How CountDownLatch works in Java :

CountDownLatch works in latch principle, here the main thread will wait for the Gate to open. Where N number of threads are responsible to open the Gate. Once all the N threads complete their execution the Gate will open for the waiting main thread and then the main thread can resume execution. The main thread calls CountDownLatch.await(). Calling await() blocks the thread until the count reaches zero and will wait until count reaches zero or its interrupted by another Thread.  

Other N threads must have reference of the latch object, they will notify the CountDownLatch object that they have completed their task by calling the countDown() method. Each call to countDown() method decreases the initial count of CountDownLatch by 1. So, when all N threads have called this method, count reaches to zero, and main thread is allowed to resume its execution past await() method.

Example of CountDownLatch:

Consider we are developing a restaurant ordering system for a popular restaurant. Where you have assigned to develop a sub module. Where the Kitchen staff sees the dishes on a order on their screen ,prepare them and confirm preparation of the order when completed. When a waiter sees the completion indication of an Order he collects the items and takes them to the table.

Here the Order is the main thread which will waits for all N dishes to complete. Arriving upon an Order the module will initialize a CountDownLatch with the number of dishes the Order consists of. And the Order will waits by calling the await() method on the latch. Each dishes will call countDown() when completed. Once the count reaches zero, means all the dishes are completed for the Order. Now the Order can resume execution and notify to the screen about the completion status. Waiter sees the completion indication and collects the items and takes them to the table.

 This is The Order class. Which has a name and a list of dishes and the table  number for which the order is for. The order awaits() on the latch for all  dishes to complete. Once all the dishes are completed then it resumes and  notify the waiter by printing the Order is Completed.

package com.tuturself.cdl;

import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * This is The Order class. Which has a name and a list of dishes and the table
 * number for which the order is for. The order awaits() on the latch for all
 * dishes to complete. Once all the dishes are completed then it resumes and
 * notify the waiter by printing the Order is Completed
 * 
 * @author Ninja Panda
 *
 */
public class Order implements Runnable {

 private final String name;
 private final int tableNo;
 private final List < Dish > dishes;
 private final CountDownLatch latch;

 /**
  * @param name
  * @param tableNo
  * @param dishes
  * @param latch
  */
 public Order(String name, int tableNo, List < Dish > dishes, CountDownLatch latch) {
  super();
  this.name = name;
  this.tableNo = tableNo;
  this.dishes = dishes;
  this.latch = latch;
 }

 @Override
 public void run() {
  try {
   System.out.println("Order :" + name + " for table no :" + tableNo + " -- preperation started.");
   for (Dish dish: dishes) {
    new Thread(dish).start();
   }
   // latch waits till the count becomes 0 by the call of countDown() from
   // all the order this way we can make sure that the execution of main thread only
   // finishes once all the 3 dishes are prepared
   this.latch.await();
  } catch (InterruptedException ex) {
   System.out.println("Order can not be completed.");
  }
  System.out.println("Order is Completed" + this.toString());
 }

 @Override
 public String toString() {
  return "Order [name=" + name + ", for TableNo=" + tableNo + ", with dishes=" + dishes + "]";
 }
}

This is the Dish class with the Dish name. Every dish calls countDown() on  latch when completed.

package com.tuturself.cdl;

import java.util.concurrent.CountDownLatch;

/**
 * This is the Dish class with the Dish name. Every dish calls countDown() on
 * latch when completed
 * 
 * @author Ninja Panda
 *
 */
public class Dish implements Runnable {

 private final String name;
 private final CountDownLatch latch;

 /**
  * @param name
  * @param latch
  */
 public Dish(String name, CountDownLatch latch) {
  super();
  this.name = name;
  this.latch = latch;
 }

 @Override
 public void run() {
  try {
   Thread.sleep(1000);
   System.out.println(name + " Dish is Done.");
   this.latch.countDown();
  } catch (InterruptedException ex) {
   System.out.println("Error while cooking Dish:" + name);
  }
 }

 @Override
 public String toString() {
  return name;
 }
}

Order Management System:

package com.tuturself.cdl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * Order Management System
 * 
 * @author Ninja Panda
 *
 */
public class OMS {

 public static void main(String args[]) {
  final CountDownLatch latch = new CountDownLatch(3);
  Dish pasta = new Dish("Pasta Carbonara", latch);
  Dish chicken = new Dish("Butter chicken", latch);
  Dish rice = new Dish("Glorified rice", latch);

  List < Dish > dishes = new ArrayList < Dish > () {
   {
    add(pasta);
    add(chicken);
    add(rice);
   }
  };

  // STRAT the order preperation 
  Order order = new Order("Order - 1", 110, dishes, latch);
  new Thread(order).start();
 }
}

The Output of the Program :

Order :Order - 1 for table no :110 -- preperation started.
Pasta Carbonara Dish is Done.
Butter chicken Dish is Done.
Glorified rice Dish is Done.
Order is CompletedOrder [name=Order - 1, for TableNo=110, with dishes=[Pasta Carbonara, Butter chicken, Glorified rice]]

core java 12 Java Concurrent Packages 12

FOLLOW US ON LinkedIn



Explore Tutu'rself