Countdown latches are single-use barriers that allow one or more threads to
wait for one or more other threads to do something. The sole constructor for
CountDownLatch takes an int that is the number of times the countDown method
must be invoked on the latch before all waiting threads are allowed to proceed.
import java.util.concurrent.CountDownLatch; class Driver { private static int N = 10; public static void main(String[] args) 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 System.out.println("Oh yeah! done signal finished."); } private static void doSomethingElse() { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 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() { System.out.println("working..."); } }
另一例:
// Simple framework for timing concurrent execution public static long time(Executor executor, int concurrency, final Runnable action) throws InterruptedException { final CountDownLatch ready = new CountDownLatch(concurrency); final CountDownLatch start = new CountDownLatch(1); final CountDownLatch done = new CountDownLatch(concurrency); for (int i = 0; i < concurrency; i++) { executor.execute(new Runnable() { public void run() { ready.countDown(); // Tell timer we're ready try { start.await(); // Wait till peers are ready action.run(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { done.countDown(); // Tell timer we're done } } }); } ready.await(); // Wait for all workers to be ready long startNanos = System.nanoTime(); start.countDown(); // And they're off! done.await(); // Wait for all workers to finish return System.nanoTime() - startNanos; }
Note that the method uses three countdown latches. The first, ready, is used
by worker threads to tell the timer thread when they’re ready. The worker threads
then wait on the second latch, which is start. When the last worker thread
invokes ready.countDown, the timer thread records the start time and invokes
start.countDown, allowing all of the worker threads to proceed. Then the timer
thread waits on the third latch, done, until the last of the worker threads finishes
running the action and calls done.countDown. As soon as this happens, the timer
thread awakens and records the end time.