第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 | 边城网事