当前位置: 首页 > Thinking in Java > 正文

第21章 – 并发 – 新类库中构件 – CountDownLatch

第21章 – 并发 – 新类库中构件 – CountDownLatch

 

1. CountDownLatch 简介

   CountDownLatch 有一个初始化count,当这个count不为0时,线程可以调用这个类的await()方法等待.

   其他线程可以调用该类的countDown()方法,使得count计数减1,当这个count计数变成0时,所有在该对象

   上await的线程将自动重新唤醒.

   只有在调用该类的await()方法出会阻塞当前线程,调用countDown()则不会.

   另外,当count计数为0后,不能重置count计数为初始值. 

 

 

2. 典型用法

 

   (1) 在一个线程(Driver)中使用一个CountDownLatch startSignal,该CountDownLatch的计数为1

       另外N个Worker线程的run开头都调用startSignal.await()暂时先阻塞着.当Driver的准备工作做完

       之后,调用startSignal.countDown()方法,使得计数为0,则在startSignal阻塞的Worker线程都可以

       运行了.

 

       而在Woker线程中,也使用了一个CountDownLatch doneSignal,初始化时,有多少个Worker就有将count计数

       初始化为多少.Driver初始化完成后,启动所有Worker,并通过调用doneSignal.await()等待每一个Worker运行完成.

       每个Worker完成后,调用doneSignal的CountDown,所有的Worker都运行完毕后,doneSignal的count计数为0.

       Driver线程重新开始运行,并做一些收尾工作.

 

       代码如下:

class Driver 
       { 
			   void main() throws InterruptedException 
			   {
			     CountDownLatch startSignal = new CountDownLatch(1);
			     CountDownLatch doneSignal = new CountDownLatch(N);
			
			     for (int i = 0; i < N; ++i) // 创建worker线程,worker创建后在startSignal上阻塞
			       new Thread(new Worker(startSignal, doneSignal)).start();
			
			     doSomethingElse();            // 做一些初始化工作
			     startSignal.countDown();      // 初始化工作完成后,使得Worker线程可以正常只想能够了
			     doSomethingElse();
			     doneSignal.await();           // 等待Worker线程全部完成
			     doSomethingElse();            // 可以做一些收尾工作
			   }
			 }
			
			 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(); //表示该Worker已经完成了
			      } 
			      catch (InterruptedException ex) {} // return;
			   }
			
			   void doWork() { ... }
			 }

 

 (2) 另一种典型用法是,将一个问题分成 N 个部分,用执行每个部分并让锁存器倒计数的 Runnable 来描述每个部分,

       然后将所有 Runnable 加入到 Executor 队列。当所有的子部分完成后,协调线程就能够通过 await。

       (当线程必须用这种方法反复倒计数时,可改为使用 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();           // 等待所有Woker结束
			   }
			 }
			
			 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(int i) { ... }
			 }

 

赞 赏

   微信赞赏  支付宝赞赏


本文固定链接: https://www.jack-yin.com/coding/thinking-in-java/2136.html | 边城网事

该日志由 边城网事 于2015年03月18日发表在 Thinking in Java 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 第21章 – 并发 – 新类库中构件 – CountDownLatch | 边城网事
关键字: ,

第21章 – 并发 – 新类库中构件 – CountDownLatch 暂无评论

发表评论

快捷键:Ctrl+Enter