前言
Semaphore是一个线程同步结构,用于在线程之间传递信号以免出现信号丢失,或者像锁一样保护一个关键区域。Java5之后, java.util.concurrent中提供了Semaphore的实现,我们不再自行实现,而是了解其原理。
1. 简单的Semaphore实现
public class Semaphore{
private boolean signal=false;
public synchronized take(){
this.signal=true;
this.notify();
}
public synchronized release() throws InterruptedException{
while(!this.signal)
wait();
this.signal=false;
}
}
take()
方法发出了一个存放在Semaphore内部的信号,而release()
方法则等待一个信号,当收到信号后,signal
被置为false
,方法结束。
使用该Semaphore
可以避免错失某些信号,如果某个线程在调用release()
等待之前调用take()
,那么调用release()
方法的线程依然知道take()
已经被某个线程调用过了,因为Semaphore内部保存了take方法发出的信号。方法名take和release来源于将Semaphore当做锁来使用的场景。
2. 限制Semaphore的计数上限
public class BoundedSemaphore{
private int signals=0;
private int bound=0;
public BoundedSemaphore(int upperBound){
this.bound=upperBound;
}
public synchronized take() throws InterruptedException{
while(this.signals==bound)
wait();
this.signals++;
this.notify();
}
public sychronized release() throws InterruptedException{
while(this.signal==0)
wait();
this.signal--;
this.notify();
}
}
在这里,当信号数达到上限时,take()
方法将阻塞新的信号产生请求,直到某个请求调用release()
方法后,被阻塞于take方法的线程才能传递自己的信号。
这里对信号数的上限做限制,保证临界区可以被上限bound
个线程锁访问。
3. 把Semaphore当锁用
当信号量的上限为1时,即可将Semaphore当做锁来使用,如下:
...
BoundedSemaphore semaphore = new BoundedSemaphore(1);
...
semaphore.take();
try{
//业务代码
} finally {
semaphore.release();
}
...
必须注意,release 方法应当在 finally 块中被执行。这样可以保在关键区域的代码抛出异常的情况下,信号也一定会被释放。