同步工具类之 CountDownLatch

来源:互联网 发布:辐射检测软件 编辑:程序博客网 时间:2024/05/03 00:42
CountDownLatch 是一个同步工具类,它可以让一个或多个线程处于等待状态,直到其它的线程执行完毕再执行。

CountDownLatch 使用一个给定的计数值初始化,调用countDown()方法会使计数值减1,处于等待状态的方法在计数值变为0前一直阻塞,当计数值变为0时所有处于等待状态的线程会被释放,这个过程是一次性的,计数值不能被重置。如果需要重置计数值循环这个过程,可以考虑使用CyclicBarrier.

CountDownLatch 作为一个同步工具类可以被用作多种目的。比如将初始计数值设置为1就像设置了一个开关或者一扇门,所有线程调用await()方法在这扇门处处于等待状态,当一个线程调用countDown()方法后,计数值变为0,门会被打开,所有处于等待状态的线程开始执行。将初始值设置为N,可以让一个线程处于等待状态,等待N个线程完成后,或者某个动作被执行N次后再开始执行。像下面的例子一样:

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();            //所有Worker线程都处于等待状态,只执行doSomethingElse()      startSignal.countDown();      //准许所有Worker线程开始执行      doSomethingElse();     doneSignal.await();           //等待所有Worker线程执行完毕    } } 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(); //所有Worker线程执行到这里变为等待状态,在 startSignal.countDown()调用后继续执行        doWork();        doneSignal.countDown();      } catch (InterruptedException ex) {} // return;   }   void doWork() { ... } }

另一个典型的用法就是将一个问题分解成多个线程来执行,主线程等待所有的子线程执行完毕后,主线程再继续执行。

class Driver2 {    void main() throws InterruptedException {     CountDownLatch doneSignal = new CountDownLatch(N);     Executor e = ...     for (int i = 0; i < N; ++i) //启动多个子线程来处理问题        e.execute(new WorkerRunnable(doneSignal, i));     doneSignal.await();           //等待所有子线程处理完毕  doSomethingElse();   } } 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() { ... } }


原创粉丝点击