/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain. Use, modify, and * redistribute this code in any way without acknowledgement. */ package java.util.concurrent; /** * A synchronization aid that allows one or more threads to wait until * a set of operations being performed in other threads completes. * *

A CountDownLatch is initialized with a given * count. The {@link #await} methods block until the current * {@link #getCount count} reaches zero due to invocations of the * {@link #countDown} method, after which all waiting threads are * released and any subsequent invocations of {@link #await} return * immediately. This is a one-shot phenomenon -- the count cannot be * reset. If you need a version that resets the count, consider using * a {@link CyclicBarrier}. * *

A CountDownLatch is a versatile synchronization tool * and can be used for a number of purposes. * A CountDownLatch initialized with a count of one serves as a simple on/off * latch, or gate: all threads invoking {@link #await} wait at the gate until * it is opened by a thread invoking {@link #countDown}. * A CountDownLatch initialized to N can be used to make * one thread wait until N threads have completed some action, or some * action has been completed N times. *

A useful property of a CountDownLatch is that it doesn't * require that threads calling countDown wait for the count to reach zero * before proceeding, it simply * prevents any thread from proceeding past the {@link #await wait} until * all threads could pass. * *

Sample usage: Here is a pair of classes in which a group * of worker threads use two countdown latches: *

* *
 * class Driver { // ...
 *   void main() throws InterruptedException {
 *     CountDownLatch startSignal = new CountDownLatch(1);
 *     CountDownLatch doneSignal = new CountDownLatch(N);
 *
 *     for (int i = 0; i < N; ++i) // create and start threads
 *       new Thread(new Worker(startSignal, doneSignal)).start();
 *
 *     doSomethingElse();            // don't let run yet
 *     startSignal.countDown();      // let all threads proceed
 *     doSomethingElse();
 *     doneSignal.await();           // wait for all to finish
 *   }
 * }
 *
 * class Worker implements Runnable {
 *   private final CountDownLatch startSignal;
 *   private final CountDownLatch doneSignal;
 *   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
 *      this.startSignal = startSignal;
 *      this.doneSignal = doneSignal;
 *   }
 *   public void run() {
 *      try {
 *        startSignal.await();
 *        doWork();
 *        doneSignal.countDown();
 *      }
 *      catch (InterruptedException ex) {} // return;
 *   }
 *
 *   void doWork() { ... }
 * }
 *
 * 
* *

Another typical usage would be to divide a problem into N parts, describe each part * with a Runnable that executes that portion and counts down on the latch, and queue all * the Runnables to an Executor. When all sub-parts are complete, the coordinating thread * will be able to pass through await. * *

 * class Driver2 { // ...
 *   void main() throws InterruptedException {
 *     CountDownLatch doneSignal = new CountDownLatch(N);
 *     Executor e = ...
 *
 *     for (int i = 0; i < N; ++i) // create and start threads
 *       e.execute(new WorkerRunnable(doneSignal, i));
 *
 *     doneSignal.await();           // wait for all to finish
 *   }
 * }
 *
 * class WorkerRunnable implements Runnable {
 *   private final CountDownLatch doneSignal;
 *   private final int i;
 *   Worker(CountDownLatch doneSignal, int i) {
 *      this.doneSignal = doneSignal;
 *      this.i = i;
 *   }
 *   public void run() {
 *      try {
 *        doWork(i);
 *        doneSignal.countDown();
 *      }
 *      catch (InterruptedException ex) {} // return;
 *   }
 *
 *   void doWork() { ... }
 * }
 *
 * 
* * @since 1.5 * @spec JSR-166 * @revised $Date: 2003/06/23 02:26:16 $ * @editor $Author: brian $ */ public class CountDownLatch { private final ReentrantLock lock = new ReentrantLock(); private final Condition zero = lock.newCondition(); private int count; /** * Constructs a CountDownLatch initialized with the given * count. * * @param count the number of times {@link #countDown} must be invoked * before threads can pass through {@link #await}. * * @throws IllegalArgumentException if count is less than zero. */ public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.count = count; } /** * Causes the current thread to wait until the latch has counted down to * zero, unless the thread is {@link Thread#interrupt interrupted}. * *

If the current {@link #getCount count} is zero then this method * returns immediately. *

If the current {@link #getCount count} is greater than zero then * the current thread becomes disabled for thread scheduling * purposes and lies dormant until one of two things happen: *

*

If the current thread: *

* then {@link InterruptedException} is thrown and the current thread's * interrupted status is cleared. * * @throws InterruptedException if the current thread is interrupted * while waiting. */ public void await() throws InterruptedException { lock.lock(); try { while (count != 0) zero.await(); } finally { lock.unlock(); } } /** * Causes the current thread to wait until the latch has counted down to * zero, unless the thread is {@link Thread#interrupt interrupted}, * or the specified waiting time elapses. * *

If the current {@link #getCount count} is zero then this method * returns immediately with the value true. * *

If the current {@link #getCount count} is greater than zero then * the current thread becomes disabled for thread scheduling * purposes and lies dormant until one of three things happen: *

*

If the count reaches zero then the method returns with the * value true. *

If the current thread: *

* then {@link InterruptedException} is thrown and the current thread's * interrupted status is cleared. * *

If the specified waiting time elapses then the value false * is returned. * The given waiting time is a best-effort lower bound. If the time is * less than or equal to zero, the method will not wait at all. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument. * @return true if the count reached zero and false * if the waiting time elapsed before the count reached zero. * * @throws InterruptedException if the current thread is interrupted * while waiting. */ public boolean await(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); lock.lock(); try { for (;;) { if (count == 0) return true; nanos = zero.awaitNanos(nanos); if (nanos <= 0) return false; } } finally { lock.unlock(); } } /** * Decrements the count of the latch, releasing all waiting threads if * the count reaches zero. *

If the current {@link #getCount count} is greater than zero then * it is decremented. If the new count is zero then all waiting threads * are re-enabled for thread scheduling purposes. *

If the current {@link #getCount count} equals zero then nothing * happens. */ public void countDown() { lock.lock(); try { if (count > 0 && --count == 0) zero.signalAll(); } finally { lock.unlock(); } } /** * Returns the current count. *

This method is typically used for debugging and testing purposes. * @return the current count. */ public long getCount() { lock.lock(); try { return count; } finally { lock.unlock(); } } }