一、Semaphore简介
semaphore 也就是我们常说的信号灯,semaphore 可以控制同时访问的线程个数,通过 acquire 获取一个许可,如果没有就等待,通过 release 释放一个许可。有点类似限流的作用。
二、Semaphore使用案例
semaphore叫信号灯的原因也和他的用处有关,比如某商场就3 个停车位,每个停车位只能停一辆车,如果这个时候来了 10 辆车,必须要等前面有空的车位才能进入。
定义一个停车的线程,每次都先去获取令牌(acquire),然后再释放令牌(release)
public class Car extends Thread {
private Semaphore semaphore;
private int num;
public Car(Semaphore semaphore,int num){
this.semaphore = semaphore;
this.num = num;
}
@Override
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();
}
}
}
创建10个线程。模拟10个车辆,Semaphore初始化创建3个令牌模拟3个停车位
public class SemaphoreDemo {
static Semaphore semaphore = new Semaphore(3);
public static void main(String[] args) {
for(int i=0;i<10;i++) {
new Car(semaphore,i).start();
}
}
}
运行结果
第0辆车占用停车位
第8辆车占用停车位
第4辆车占用停车位
第0辆车开走了
第3辆车占用停车位
第4辆车开走了
第8辆车开走了
第7辆车占用停车位
第1辆车占用停车位
第3辆车开走了
第5辆车占用停车位
第1辆车开走了
第9辆车占用停车位
第7辆车开走了
第2辆车占用停车位
第5辆车开走了
第6辆车占用停车位
第9辆车开走了
第2辆车开走了
第6辆车开走了
Process finished with exit code 0
三、源码分析
在分析过AQS,锁,Condition,CountDownLatch等并发工具的源码,Semaphore的源码没有必要再一行行代码解释了。
从 Semaphore 的功能来看,我们基本能猜测到它的底层实现一定是基于 AQS 的共享锁,因为需要实现多个线程共享一个令牌池,创建Semaphore 实例的时候,需要一个参数 permits,这个基本上可以确定是设置给 AQS 的 state 的,然后每个线程调用 acquire 的时候,执行 state = state - 1,release 的时候执行 state = state + 1,当然,acquire 的时候,如果 state = 0,说明没有资源了,需要等待其他线程 release。
本文是综合自己的认识和参考各类资料(书本及网上资料)编写,若有侵权请联系作者,所有内容仅代表个人认知观点,如有错误,欢迎校正; 邮箱:1354518382@qq.com 博客地址:https://blog.csdn.net/qq_35576976/