/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package java.util.concurrent; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.*; /** * 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 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 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 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 an {@link #await await} 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. (When threads must repeatedly * count down in this way, instead use a {@link CyclicBarrier}.) * *
* 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;
* WorkerRunnable(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
* @author Doug Lea
*/
public class CountDownLatch {
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
private static final class Sync extends AbstractQueuedSynchronizer {
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
public int tryAcquireShared(int acquires) {
return getState() == 0? 1 : -1;
}
public boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
private final Sync sync;
/**
* 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.sync = new Sync(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: *
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: *
If the specified waiting time elapses then the value false * is returned. * 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 { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } /** * 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() { sync.releaseShared(1); } /** * Returns the current count. *
This method is typically used for debugging and testing purposes. * @return the current count. */ public long getCount() { return sync.getCount(); } /** * Returns a string identifying this latch, as well as its state. * The state, in brackets, includes the String * "Count =" followed by the current count. * @return a string identifying this latch, as well as its * state */ public String toString() { return super.toString() + "[Count = " + sync.getCount() + "]"; } }