什么是信号量(semaphore)
- 是一种JDK内置同步器,通过他可以实现多线程对公共资源的并发访问请求
- 可以看成一个计数器,当计数器的值小于许可最大值时,所有acquire方法线程都可以得到一颗许可继续执行,而调用release方法则可以让计数器的值减一
常用的重要方法
1、public Semaphore(int permits)
// 创建一个给定许可数量的信号量对象,且默认以非公平锁方式获取资源
2、public Semaphore(int permits, boolean fair)
// 创建一个给定许可数量的信号量对象,且是否公平方式由传入的fair布尔参数值决定
3、public void acquire()
// 从此信号量获取一个许可,当许可数量小于零时,则阻塞等待
4、public void acquire(int permits)
// 从此信号量获取permits个许可,当许可数量小于零时,则阻塞等待,但是当阻塞等待的线程被唤醒后发现被中断过的话则会抛InterruptedException异常
5、public void acquireUninterruptibly(int permits)
// 从此信号量获取permits个许可,当许可数量小于零时,则阻塞等待,但是当阻塞等待的线程被唤醒后发现被中断过的话不会抛InterruptedException异常
6、public void release()
// 释放一个许可
7、public void acquire(int permits)
// 释放permits个许可
实现原理
- semaphore类的实现是基于AQS同步器来实现的,不管是公平还是非公平都是基于AQS的共享模式,只是在操作逻辑有差异。
- 内部子类Syn是公平模式FairSync和非公平模式NonfairSync类的抽象父类
- 其中提供两个构造函数,两个参数为许可最大数和是否使用公平模式。
非公平模式实现
- 提供了非公平模式信号量获取的方法nonfairTryAcquireShared
- 在许可数量允许的情况下(remaining<0),可以让所有线程进行自旋操作(CAS)
- 当剩余信号量小于0时则返回负数(return remaining),导致线程进入等待队列(AQS)
- tryReleaseShared方法则提供释放信号量操作
- 通过自旋操作CAS将信号量增加到当前剩余许可数上
公平模式的实现
- 公平模式和非公平模式最主要差异是在获取信号量时的机制
- 不同的地方就在方框的两行代码,它会检查是否已经存在等待队列,如果有就直接(return -1)让AQS同步器将当前线程进入等待队列
例子