Semaphore 功能演示
semaphore也就是我们常说的信号灯,semaphore可以控制同时访问的线程个数,通过 acquire 获取一个许可,如果没有就等待,通过release释放一个许可。有点类似限流的作用。叫信号灯的原因也和他的用处有关,比如某商场就5个停车位,每个停车位只能停一辆车,如果这个时候来了10辆车,必须要等前面有空的车位才能进入。
- 代码演示
- Semaphore比较常见的就是用来做限流操作了。
简单了解一下Semaphore源码
从 Semaphore 的功能来看,我们基本能猜测到它的底层实现一定是基于AQS的共享锁,因为需要实现多个线程共享一个领排池。
创建 Semaphore 实例的时候,需要一个参数 permits,这个基本上可以确定是设置给 AQS 的 state 的,然后每个线程调用 acquire 的时候,执行 state = state - 1, release 的时候执行 state = state + 1,当然,acquire 的时候,如果 state = 0,说明没有资源了,需要等待其他线程 release。
Semaphore 分公平策略和非公平策略
if (hasQueuedPredecessors())
return -1;
区别仅仅在于,公平锁会先判断链表中是否已经存在了节点,如果存在了则直接进入链表等待,而非公平锁直接判断 state 的值是否< 0 (进行了一次插队操作)
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
//是否被中断
if (Thread.interrupted())
throw new InterruptedException();
//对 state 的值- 1,如果结果 >= 0表示没有超过限制的线程数,直接放行,如果超过了则添加到一个双向链表中
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
- release() 方法
public final boolean releaseShared(int arg) {
//对 state 进行了 +1 操作
if (tryReleaseShared(arg)) {
//唤醒头节点的线程
doReleaseShared();
return true;
}
return false;
}
由于大部分的代码和CountDownLatch的是完全一样,都是基于共享锁的实现,所以也就没必要再花时间来分析了。
CyclicBarrier 功能演示
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续工作。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用 await 方法告诉 CyclicBarrier 当前线程已经到达了屏障,然后当前线程被阻塞。
CyclicBarrier(int parties,Runable runa) 当存在需要所有的子任务都完成时,才执行主任务,这个时候就可以选择使用CyclicBarrier
- 代码演示
-
我们创建了 CyclicBarrier 对象并且设置了阻塞的线程数和子线程,当我们的三个测试线程都被阻塞后,执行子线程,并且被阻塞的线程数达到了最大阻塞个数,全部放行。
-
注意点
- 对于指定计数值parties,若由于某种原因,没有足够的线程调用CyclicBarrier的await,则所有调用await的线程都会被阻塞
- 同样的CyclicBarrier也可以调用await(timeout, unit),设置超时时间,在设定时间内,如果没有足够线程到达,则解除阻塞状态,继续工作;
- 通过 reset 重置计数,会使得进入 await 的线程出现 BrokenBarrierException;
- 如果采用是 CyclicBarrier(int parties, Runnable barrierAction) 构造方法,执行 barrierAction 操作的是最后一个到达的线程
- CyclicBarrier 可以有不止一个栅栏,因为它的栅栏(Barrier)可以重复使用(Cyclic)
- CyclicBarrier 相比 CountDownLatch 来说要简单很多,主要的区别就是栅栏可以重复使用,源码实现是基于ReentrantLock 和 Condition 的组合使用。
- 举个例子:司令下达命令,要求10个士兵一起去执行任务。这时,就会要求10个士兵先集合报道,接着,一起去执行任务。当任务执行完毕时,司令就会宣布任务执行完成。然后下一次召集的时候,还得等着10个士兵集合了才能出发。