计数信号量(Counting Semaphore)用来控制同时访问某个特定资源的操作数量,或者执行某个特定操作的数量。计数信号量还可以用来实现某种资源池或者对容器加边界。
Semaphore中管理着一组虚拟的许可(permit),许可的初始数量可通过构造函数来指定,在执行操作时可以首先获得许可(只要还有剩余的许可),并在使用以后释放许可。如果没有许可,那么acquire将阻塞知道有许可(或者知道被中断或者操作超时)。release方法将返回一个许可给信号量。计算信号量的一种简化形式是二值信号量,即初始值为1的Semaphore二值信号量可以用作互斥体(mutex),并具备不可重入的加锁语义:谁拥有这个唯一的许可,谁就拥有了互斥锁。如果你想学习Python可以来这个群,首先是二二零,中间是一四二,最后是九零六,里面有大量的学习资料可以下载、
Semaphore可以用于实现资源池,例如数据库连接池。我们可以构造一个固定长度的资源池,当池为空时,请求资源会失败,但你真正希望的行为是阻塞而不是失败,并且当池非空时解除阻塞。如果将Semaphore的初始值初始化为池的大小,并在池中获取一个资源之前首先调用acquire获取一个许可,在将资源返回给池之后调用release释放许可,那么acquire将一致阻塞直到资源池不为空。(在构造阻塞对象池时,一种更简单的方法是使用阻塞队列,不过阻塞队列没有计数信号量中“计数”的功能)。
同样,你也可以使用Semaphore将任何一种容器变成有界阻塞容器,见代码:
public class BoundedHashSet<T> {
private final Set<T> set;
private final Semaphore sem;
public BoundedHashSet(int bound) {
this.set = Collections.synchronizedSet(new HashSet<T>());
sem = new Semaphore(bound);
}
public boolean add(T o) throws InterruptedException {
sem.acquire();
boolean wasAdded = false;
try{
wasAdded = set.add(o);
return wasAdded;
}
finally {
if(!wasAdded)
sem.release();
}
}
public boolean remove(Object o) {
boolean wasRemoved = set.remove(o);
if(wasRemoved)
sem.release();
return wasRemoved;
}
}