/* * @(#)CountDownLatch.java 1.5 04/02/09 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ 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() + "]"; } }