juc包之CountDownLatch与CyclicBarrier
CountDownLatch与CyclicBarrier各自的实现原理
CountDownLatch类
示例代码: (在CountDownLatch类的注释上方提供了两种使用方式)
第一种
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(); doSomethingElse(); doneSignal.await(); } } 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) {} } void doWork() { //something to do } }
先让所有Worker等Driver去唤醒,然后Driver等所有Worker执行完再唤醒
第二种
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(); // wait for all to finish } } 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() { ... } }
让Drive等待所有Worker运行完毕(注释说这种写法可以用CyclicBarrier代替)
看一下几个核心方法
- CountDownLatch构造方法
初始化主要是给state变量设置了值,并且该值不能小于0
- CountDownLatch的countdown方法
countdown执行了Sync内部类的releaseShared方法,该方法先执行了tryReleaseShared方法,返回true才会去执行doReleaseShared方法
该方法首先判断state值是否为0,如果为0,直接返回false,代表没有资源可以释放了,要是不为0,则将state值减1,并将结果更新给state变量,然后判断-1后的值是否为0,如果为0,则返回true.所以返回true的含义就是在此次释放资源后已经没有需要释放的资源了.
该方法是在资源全部被释放后才会执行的.首先获取队列的head节点,并且判断head节点不为null也不为tail(head只有已经唤醒过才有可能与tail节点相同).然后获取head的waitStatus.如果waitStatus是Signal则会去唤醒该节点线程,如果执行期间head节点被替换了,则会继续循环,否则就跳出.
- CountDownLatch的await方法
await执行了Sync内部类的acquireSharedInterruptibly方法,该方法首先判断当前线程是否中断了,如果中断直接抛出错误,否则执行tryAcquireShared方法,当返回负数时才会去执行doAcquireSharedInterruptibly方法
判断当前state变量值是否为0,只有当不为0才会返回负数-1,代表还有资源未释放
该方法内部与ReentranLock类的acquiredQueued很像,都是遍历链表节点,去获取资源,获取失败则会调用LockSupport的park方法将其挂起,且设置节点为SIGNAL.获取成功则会调用setHeadAndPropagate方法将所有未取消的节点都唤醒
juc包之CountDownLatch与CyclicBarrier
http://windwest.cn/2022/01/19/juc包之CountDownLatch与CyclicBarrier/