信号量Semaphore是一个控制访问多个共享资源的计数器,和CountDownLatch一样,其本质上是一个“共享锁”。
Semaphore介绍
Semaphore在API是这么介绍的:
一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前阻塞每一个acquire(),然后在获得该许可。每个release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。
Semaphore通常用于控制当前访问某些资源的线程个数,并提供了同步机制
举个简单的例子来阐述Semaphore:
假如有这么一个场景,一个厕所有5个坑位,刚开始全部空着,来了3个人,占了3个坑,然后又来了3个人,这个时候由于只有2个坑位,所以只能2个人,另外一个人只能候着,直到坑位空出来。包括后面来的人,也必须在外面候着。当坑位空着了,另外等待的人可以随机进去还是按照先来后到的顺序进去,这取决于构造Semaphore对象传入的参数选项。
从程序的角度来看,厕所坑位就相当于信号量Semaphore,其中许可数为5,上厕所的人就相当于线程,当进来一个人许可数就减1,当没有了坑位(许可就为0了)
信号量是一个非负整数(大于等于1),当一个线程访问共享资源时,它必须先获取Semaphore,当Semaphore>0时,获取该资源并使Semaphore-1,若Semaphore为0,则表示全部的共享资源已经被其他线程占用,必须等待其他线程释放资源。
Semaphore分析
从Semaphore源码来看,其内部结构包含了FairSync(公平锁)和NonfairSync(非公平锁),基础内部类Sync,其中Sync继承AQS(AQS很重要)。
构造函数
Semaphore提供2个构造函数:
- Semaphore(int permits),创建具有给定的许可数和非公平的公平设置的 Semaphore
- Semaphore(int permits, boolean fair),创建具有给定的许可数和给定的公平设置的 Semaphore
Semaphore默认选择非公平锁,当信号量Semaphore=1时,它可以当做互斥锁使用。其中0,1就相当于它的状态,当为1时表示其他线程可以获取;当为0时,即其他线程必须等待。
信号量获取
Semaphore提供了acquire()方法来获取一个许可
内部调用AQS的acquireSharedInterruptibly(int arg),该方法以共享模式获取同步状态:
信号量释放
Semaphore提供release()来释放许可
内部调用的AQS中的releaseShared():
代码示例
就拿上面的厕所坑位来举例:
运行结果如下: