Count-Down Latch

The java.util.concurrent.CountDownLatch class implements a count-down latch that allows one or more threads to wait until the latch goes up, and then the waiting threads are allowed to proceed. The latch goes up depending on one or more other threads performing a specific number of countdown operations.

The CountDownLatch class provides the following constructor to create a count-down latch.

CountDownLatch(int count)

Creates a CountDownLatch initialized with the given count. The count specifies the number of times the countDown() method must be invoked to raise the latch to allow threads waiting on the await() method to pass through.

A count-down latch is created with an initial count. One or more threads can call the await() method of the latch to wait until the count reaches zero. The count is decremented by calls to the countDown() method of the latch by one or more other threads. Note that it is the number of calls to the countDown() method that raises the latch, independent of the number of threads involved. The countDown() method is used in tandem with the await() method to operate the latch. The latch can only go up once, and therefore cannot be reused.

Click here to view code image

void await() throws InterruptedException
boolean await(long timeout, TimeUnit unit) throws InterruptedException

Both methods cause the current thread to wait until one of the following events occurs: The latch count reaches 0, the thread is interrupted, or if any specified waiting time has elapsed.

In the first method, it is possible that the current thread may wait forever, if the count never reaches 0.

The second method returns true if the count reached 0 and false if the waiting time elapsed before the count reached 0.

void countDown()

Decrements the current count of the latch if it is greater than 0, releasing all waiting threads if the new count reaches 0. Nothing happens if the current count is already 0.

Given that the latch below is shared by threads t1, t2, and t3:

Click here to view code image

CountDownLatch latch = new CountDownLatch(3);    // (1) Latch count is 3.

Threads t1 and t2 call the await() method and wait at (2) and (3), respectively, for the latch to be raised:

Click here to view code image

// Thread t1:
latch.await();            // (2) Waiting for latch to be raised.

// Thread t2:
latch.await();            // (3) Waiting for latch to be raised.

Thread t3 calls the countDown() method on the latch, decrementing the count each time. Note that the thread calling the countDown() method does not wait for the count to reach 0. The count reaches 0 when the call at (4) is executed, upon which the latch is raised, and waiting threads t1 and t2 can continue execution past the await() method call.

Click here to view code image

// Thread t3:
latch.countDown();

latch.countDown(),

latch.countDown();         // (4) Count reaches 0. Latch released at (2) and (3).

Example 23.15 illustrates a typical scenario where an administrator thread (in this case, the main thread) submits tasks (defined by the Task class at (7)) to individual threads and uses two count-down latches to start and wait for the tasks to finish.

The two latches, startLine and finishLine, are declared at (1) and (2), respectively. The startLine latch is an on/off latch with a count of 1. All submitted tasks invoke the await() method at (9) to wait until the startLine latch is raised by the main thread by invoking the countDown() method at (5) to decrement the count to 0.

The finishLine latch is a latch with a count of N. It is the converse of the startLine latch. All submitted tasks count down the finishLine latch by invoking the count-Down() method at (10) and continue execution. The main method invokes the await() on the finishLine latch and waits until the latch is raised by all submitted tasks, decrementing the count to 0.

Example 23.15 Count-Down Latch

Click here to view code image

package synchronizers;
import static java.lang.System.out;
import java.util.concurrent.*;
public class CountDownLatchTest {
  public static final int N = 3;
  public static void main(String[] args) throws InterruptedException {
    CountDownLatch startLine = new CountDownLatch(1);              // (1)
    CountDownLatch finishLine = new CountDownLatch(N);             // (2)
    ExecutorService es = Executors.newFixedThreadPool(N);          // (3)
    String threadName = Thread.currentThread().getName();
    try {
      for (int i = 0; i < N; ++i) {    // (4) Submit tasks.
        es.submit(new Task(startLine, finishLine));
      }
      out.println(threadName + “: Let all tasks proceed.”);
      startLine.countDown();           // (5) Count down to let all tasks proceed.
      finishLine.await();              // (6) Wait for all tasks to finish.
      out.println(threadName + “: All tasks done.”);
    } finally {
      es.shutdown();
    }
  }
}
class Task implements Runnable {                                   // (7)
  private final CountDownLatch startLine;
  private final CountDownLatch finishLine;
  public Task(CountDownLatch start, CountDownLatch finish) {
    this.startLine = start;
    this.finishLine = finish;
  }

  @Override
  public void run() {                                               // (8)
    String threadName = Thread.currentThread().getName();
    try {
      out.println(threadName + “: Waiting to proceed.”);
      startLine.await();               // (9) Wait to proceed.
      out.println(threadName + “: Running … “);
      finishLine.countDown();          // (10) Count down the latch & continue.
      out.println(threadName + “: Latch count decremented.”);
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }
  }
}

Probable output from the program:

Click here to view code image

main: Let all tasks proceed.
pool-1-thread-3: Waiting to proceed.
pool-1-thread-2: Waiting to proceed.
pool-1-thread-1: Waiting to proceed.
pool-1-thread-1: Running …
pool-1-thread-2: Running …
pool-1-thread-2: Latch count decremented.
pool-1-thread-3: Running …
pool-1-thread-1: Latch count decremented.
pool-1-thread-3: Latch count decremented.
main: All tasks done.