CyclicBarrier、CountDownLatch以及Semaphore使用及其原理分析

640?wx_fmt=gif

CyclicBarrier、CountDownLatch以及Semaphore是Java并发包中几个常用的并发组件,这几个组件特点是功能相识很容易混淆。首先我们分别介绍这几个组件的功能然后再通过实例分析和源码分析其中设计原理。

CyclicBarrier

主要功能:

CyclicBarrier的主要功能是使1~(N-1)个线程达到某个屏障后阻塞,直到第N个线程到达该屏障后才会被打开,这是所有的线程才能继续执行下去,CyclicBarrier同时支持一个Runable对象,当所有线程到达该屏障时执行该Runable对象。

用例:

640?wx_fmt=png

输出:

Thread-0达到屏障
Thread-2达到屏障
Thread-1达到屏障
Thread-1离开屏障
Thread-2离开屏障
Thread-0离开屏障

可以看到三个线程同时达到屏障后所有线程才开始离开屏障继续运行。下面我们将分析其设计原理。

设计原理

CyclicBarrier调用await()方法是线程等待,await()方法源码如下:

640?wx_fmt=png

其内部调用的是doWait()方法,await()还有一个带超时的重载方法,功能类似。doWait()方法代码如下:

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

Generation是一个静态内部类,表明CyclicBarrier的代,表明每个CyclicBarrier执行的实例,如果当前CyclicBarrier正常执行完将会重置代,否则将会破坏代。

640?wx_fmt=png

breakBarrier方法会破坏屏障,可以看到起设置了代为破坏状态同时调用Condition的signalAll方法唤醒所有在等待的线程。

640?wx_fmt=png

nextGeneration主要作用为重置下一代,内部也会唤醒正在等待的线程同时将屏障数量复位方便下一次使用。

CountDownLatch

CountDownLatch的主要功能是实现几个计数器,使N个现场执行完成后当前线程才会继续执行下去。比如我们希望将一个事件分成多个线程去执行,执行完后进行汇总这种情景就可以使用CountDownLatch。

用例

640?wx_fmt=png

输出:

Thread-0执行完毕
Thread-1执行完毕
Thread-2执行完毕
Thread-3执行完毕
Thread-4执行完毕
主线程执行

原理分析

构造方法

640?wx_fmt=png

CountDownLatch构造函数中调用了Sync构造方法,Sync继承了AQS内容如下:

640?wx_fmt=png

设置了state,这个东西再熟悉不过了,在可重入锁中表示是否获取到锁的标志位。

我们首先看await方法,

640?wx_fmt=png

实际调用的是AQS的acquireSharedInterruptibly方法,从名字可以看出采用的是共享模式。

640?wx_fmt=png

tryAcquireShared代码在Sync中被实现如下:

640?wx_fmt=png

如果state等于0返回1,否则返回-1;state等于0说明没有对象在同步器中,线程可以继续执行下去,否则进入doAcquireSharedInterruptibly方法中,doAcquireSharedInterruptibly方法如下:

640?wx_fmt=png

这段代码就是共享模式获取节点,获取不到就进入队列中休眠,这个跟读写锁一样,知道state等于0后被唤醒。

countDown方法如下:

640?wx_fmt=png

调用的是Sync的releaseShared方法,

640?wx_fmt=png

640?wx_fmt=png

countDown方法的主要功能就是通过CAS方法减少state的值,减少成功后唤醒队列中的节点。唤醒主节点成功后doAcquireSharedInterruptibly中方法会继续执行接着判断state是否等于0,不等与继续休眠否则继续执行线程。

Semaphore

Semaphore可以控制访问线程的数量。

用例:

640?wx_fmt=png

原理分析

首先看构造方法,

640?wx_fmt=png

默认构造方法采用非公平模式。

acquire方法如下:

640?wx_fmt=png

很熟悉默认采用的是共享模式获取节点信息,跟读锁类似。

640?wx_fmt=png

 

release方法如下:

640?wx_fmt=png

acquireSharedInterruptibly方法如下:

640?wx_fmt=png

tryReleaseShared方法如下:

640?wx_fmt=png 

总结

CyclicBarrier主要用于N个线程之间互斥,当且仅当N个线程都执行到屏障处所有线程才能继续执行下去,CyclicBarrier可以被重复使用,CyclicBarrier通过可冲入锁+AQS+Condition实现,CyclicBarrier调用await方法获取可重入锁同时减少state的值,state==0时唤醒所有正在等待的线程,否则线程处于等待状态,线程间的通信主要通过Condition机制来实现。

CountDownLatch主要用于某个线程等待N个线程执行完后等待的线程接着继续执行下去,不能够重复执行,CountDownLatch通过设施AQS state值来实现,每次调用counDown方法后都去唤醒正在等待的线程,等待的线程判断state是否等于0,等于0就继续执行。

Semaphore用于控制访问线程的数量,Semaphore通过设置AQS state值来实现,调用require方法后cas减少state的值,如果state值为负数说明有更多线程正在访问代码块,这是后需要把这些线程休眠,调用release方法后重新增加state值,重新增加state值后去唤醒正在等待的线程。

640?wx_fmt=png

公众号推荐:

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值