CountDownLatch闭锁

对synchronization拓展,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

CountDownLatch用给定的计数初始化。await属于阻塞方法,直到当前计数达到零,由于countDown方法被调用,然后释放所有await等待的线程,并立即返回线程后续的await调用逻辑。CountDownLatch是一种一次性现象——计数无法重置。如果需要重新设置计数的版本,可以考虑使用CyclicBarrier。

CountDownLatch是一种通用的同步工具,可以用于多种目的。初始化一个count为1的CountDownLatch用作一个简单的on/off latch或gate:所有调用wait的线程都在gate处等待,直到它被调用countDown的线程打开。一个初始化为N的CountDownLatch可以用来让一个线程等待,直到N个线程完成了某个操作,或者某个操作已经完成了N次。

CountDownLatch的一个有用特性是,它不要求调用countDown的线程等待计数达到零才继续,它只是防止任何线程继续等待,直到所有线程都通过。

示例用法:这里有两个类,其中一组工作线程使用两个倒计时锁存器:

第一个是启动信号,它阻止任何worker继续工作,直到驱动程序准备好让它们继续工作;

第二个是一个完成信号,它允许驱动程序等待所有worker完成。

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();            // 预备工作逻辑
     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();
       doWork();
       doneSignal.countDown();
     } catch (InterruptedException ex) {} // return;
   }

   void doWork() { ... }
 }

另一种典型的用法是将一个问题分成N个部分,用一个Runnable描述每个部分,该Runnable执行该部分并在锁存器上计数,然后将所有Runnables排队到一个执行器。当所有子部件都完成时,协调线程将能够通过并等待。(当线程必须以这种方式重复倒数时,使用CyclicBarrier。)

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();           // 等待所有Worker完成逻辑操作
   }
 }

 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() { ... }
 }

内存一致性效应:在计数达到零之前,在另一个线程中调用countDown()之前的动作发生——在从相应的await()成功返回之后的动作发生之前。

CountDownLatch底层通过内部类Sync继承AbstractQueuedSynchronizer类;

计数器字段使用内存语义volatile修饰,private volatile int state;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值