文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步。
相关文章:
- 多线程的应用与原理分析1
- 多线程的应用与原理分析2(线程的状态)
- 多线程的应用与原理分析3(原子性、可见性、有序性)
- 多线程的应用与原理分析4(synchronized)
- 多线程的应用与原理分析5(ReentrantLock)
- 多线程的应用与原理分析6(ReentrantLock)
- 多线程的应用与原理分析7(Condition)
- 多线程的应用与原理分析8(countdownlatch)
- 多线程的应用与原理分析9(原子操作)
- 多线程的应用与原理分析10(Semaphore)
- 多线程的应用与原理分析11(线程池)
Semaphore
semaphore也就是我们常说的信号灯,semaphore可以控制同时访问的线程个数,通过acquire获取一个许可,如果没有就等待,通过release释放一个许可。有点类似限流的作用。叫信号灯的原因也和他的用处有关,比如某商场就5个停车位,每个停车位只能停一辆车,如果这个时候来了10辆车,必须要等前面有空的车位才能进入。
使用案例
package lock;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* @author zhangyu
* @version V1.0
* @ClassName: SemaphoreDemo
* @Description: Semaphore同时有几个线程执行任务
* @date 2019/1/25 11:49
**/
public class SemaphoreDemo {
public static void main(String[] args){
Semaphore semaphore=new Semaphore(5);
for(int i=0;i<10;i++){
new Car(i,semaphore).start();
}
}
static class Car extends Thread{
private int num;
private Semaphore semaphore;
public Car(int num,Semaphore semaphore){
this.num=num;
this.semaphore=semaphore;
}
public void run(){
try{
semaphore.acquire();
System.out.println("第"+num+"占用一个停车位");
TimeUnit.SECONDS.sleep(2);
System.out.println("第"+num+"车走了");
semaphore.release();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
使用场景
可以实现对某些接口访问的限流
源码分析
semaphore也是基于AQS来实现的,内部使用state表示许可数量;它的实现方式和CountDownLatch的差异点在于acquireSharedInterruptibly中的tryAcquireShared方法的实现,这个方法是在Semaphore方法中重写的
acquireSharedInterruptibly
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
tryAcquireShared
在semaphore中存在公平和非公平的方式,和重入锁是一样的,如果通过FairSync表示公平的信号量、NonFairSync表示非公平的信号量;公平和非公平取决于是否按照FIFO队列中的顺序去分配Semaphore所维护的许可,我们来看非公平锁的实现。
nonfairTryAcquireShared
自旋去获得一个许可,如果许可获取失败,也就是remaining<0的情况下,让当前线程阻塞;
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
releaseShared
releaseShared方法的逻辑也很简单,就是通过线程安全的方式去增加一个许可,如果增加成功,则触发释放一个共享锁,也就是让之前处于阻塞的线程重新运行
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
增加令牌数
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}