/* * 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; import java.util.concurrent.locks.*; /** * 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/07/08 00:46:33 $ * @editor $Author: dl $ * @author Doug Lea */ 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(); } } }