概念
计数信号量,一个初始化为1的信号量,并且它最多只能有一个permit可用,可以作为互斥锁。这通常被称为二进制信号量,因为它只有两种状态:一个可用的许可证,或零可用的许可证。当以这种方式使用时,二进制信号量具有这样的属性(与许多java.util.concurrent.locks.Lock实现不同),即“锁”可以由所有者以外的线程释放(因为信号量没有所有权的概念)。这在某些特定的上下文中可能很有用,比如死锁恢复。 该类的构造函数可选接受一个公平性参数.false时不保证线程获得许可的顺序,true反之;这里需要注意的是不定时的tryAcquire方法不适用公平性设置. 通常,用来控制资源访问的信号量应该被初始化为公平的,以确保没有线程在访问资源时被耗尽。当将信号量用于其他类型的同步控制时,不公平排序的吞吐量优势往往超过公平性考虑。
应用场景
- 用于多个共享资源的互斥使用.
- 用于并发线程数的控制.
- 流量控制
注意事项
- 同一个信号量可以重复释放,官方给的案例中,需要单独维护该信号量状态
- release()调用应该放在finally块中,避免出现异常情况下信号量无归还
- Semaphore默认采用非公平策略
官方例子
class Pool {
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
protected Object[] items = ... whatever kinds of items being managed
protected boolean[] used = new boolean[MAX_AVAILABLE];
protected synchronized Object getNextAvailableItem() {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (!used[i]) {
used[i] = true;
return items[i];
}
}
return null; // not reached
}
protected synchronized boolean markAsUnused(Object item) {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (item == items[i]) {
if (used[i]) {
used[i] = false;
return true;
} else {
return false;
}
}
return false;
}
}