计数信号量(Counting Semaphore)用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。计数信号量还可以用来实现某种资源池,或者对容器施加边界。
Semaphore中管理着一组虚拟的许可(permit),许可的初始数量可通过构造函数来指定。在执行操作时可以首先获得许可(只要还有剩余的许可),并在使用以后释放即可。如果没有许可,那么aquire将阻塞直到有许可(或者直到被中断或者操作超时)。release方法将返回一个许可给信号量。
在这种实现中不包含真正的许可对象,并且Semaphore也不会将许可与线程关联起来,因此在一个线程中获得的许可可以在另一个线程中释放。
可以将acquire操作视为是消费一个许可,而release操作是创建一个许可,Semaphore并不受限于它在创建时的初始许可数量。
计算信号量的一种简化形式是二值信号量,即初始值为1的Semaphore。二值信号量可以用作互斥体(mutex),并具备不可重入的加锁语义:谁拥有这个唯一的许可,谁就拥有了互斥锁。
Semaphore可以用于实现资源池,例如数据库连接池。我们可以构造一个固定长度的资源池,当池为空时,请求资源将会失败,但你真正希望看到的行为是阻塞而不是失败,并且当池非空时解除阻塞。如果将Semaphore的计数值初始化为池的大小,并在从池中获取一个资源之前先调用aquire方法获得一个许可,在将资源返回给池之后调用release释放许可,这样就实现了固定长度了。
同样,你可以使用Semaphore将任何一种容器变成有界阻塞容器,如下代码所示。信号量的计数值会初始化为容器容量的最大值。add操作在向底层容器中添加一个元素之前,首先需要获得一个许可。如果add操作没有添加任何元素,那么会立刻释放许可。同样remove操作释放一个许可,使更多的元素能够添加到容器中。底层的Set实现并不知道关于边界的任何信息,这是由BoundedHashSet来处理的。
作者:jiankunking