2022年1月19日21:17:57
2022年1月20日22:35:21
Semaphore
Semaphore,俗称信号量,它是操作系统中PV操作的原语在java的实现,它也是基于AbstractQueuedSynchronizer实现的。用于做流量控制,比如说高速收费站,总共有3个收费口,每次最多有3辆车缴费通过,其他的车都要在后面等待(阻塞);
应用场景
可以用于做流量控制,特别是公用资源有限的应用场景,比较著名是sentinel
Semaphore 常用方法
public void acquire() throws InterruptedException public boolean tryAcquire() public void release() public int availablePermits() public final int getQueueLength() public final boolean hasQueuedThreads() protected void reducePermits(int reduction)
设计思路
CountDownLatch
CountDownLatch(闭锁)是一个同步协助类,允许一个或多个线程等待,直到其他线程完成操作集。比如说王者荣耀,5个玩家都连接成功才能开始游戏,如果有一个玩家没连接上,另外4个玩家都需要等待连接。
CountDownLatch给定一个计数值初始化,await会阻塞方法,计数器由countDown调用达到0,count到0后会释放所有等待线程,并且随后对await方法的调用会立刻返回,这是一个一次性现的,count不会被被重置,如果需要一个重置count版本的请使用CyclicBarrier。
CountDownLatch应用场景
CountDownLatch一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。
CountDownLatch实现原理
底层基于 AbstractQueuedSynchronizer 实现,CountDownLatch 构造函数中指定的count直接赋给AQS的state;每次countDown()则都是release(1)减1,最后减到0时unpark阻塞线程;这一步是由最后一个执行countdown方法的线程执行的。
而调用await()方法时,当前线程就会判断state属性是否为0,如果为0,则继续往下执行,如果不为0,则使当前线程进入等待状态,直到某个线程将state属性置为0,其就会唤醒在await()方法中等待的线程。
CyclicBarrier介绍
字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态(屏障点)之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。
CyclicBarrier应用场景
CyclicBarrier 可以用于多线程计算数据,最后合并计算结果的场景。
利用CyclicBarrier的计数器能够重置,屏障可以重复使用的特性,可以支持类似“人满发车”的场景
CyclicBarrier关注点
1.一组线程在触发屏障之前互相等待,最后一个线程到达屏障后唤醒逻辑是如何实现的
2.删栏循环使用是如何实现的
3.条件队列到同步队列的转换实现逻辑
问题:
CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
- CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次
- CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法。
- CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程。
- CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同。CountDownLatch一般用于一个或多个线程,等待其他线程执行完
- CyclicBarrier 还可以提供一个 barrierAction,合并多线程计算结果。
- CyclicBarrier是通过ReentrantLock的"独占锁"和Conditon来实现一组线程的阻塞唤醒的,而CountDownLatch则是通过AQS的“共享锁”实现



