信号量(Semaphore)是一种控制多线程(进程)访问共享资源的同步机制,是由荷兰的Dijkstra大佬在1962年前后提出来的。
信号量机制包含以下几个核心概念:
从上图不难看出信号量的两个核心操作,P和V:
S < 0
,则阻塞当前线程S <= 0
,则唤醒一个阻塞的线程信号量一般被用来控制多线程对共享资源的访问,允许最多S个线程同时访问临界区,多于S个的线程会被P操作阻塞,直到有线程执行完临界区代码后,调用V操作唤醒。所以PV操作必须是成对出现的。
那么信号量可以用来干什么呢?
S = 1
,这样就只能有一个线程能访问临界区。很明显这是一个不可重入的锁。学习这些经典理论的时候,最好的办法还是用自己熟悉的编程语言实现一遍。Java并发包提供了一个信号量的java.util.concurrent.Semaphore
,是用AbstractQueuedSynchronizer
的共享模式实现的,以后会单独分析关于AQS相关的原理,这里不再展开描述,其核心思想是CAS。 下面是我用Java实现的一个简单的信号量,这里使用synchronized
来替代互斥锁
publicclassSemaphore {
/**
* 信号量S
*/privateint s;
publicSemaphore(int s) {
this.s = s;
}
/**
* P原语,原子操作
* <p>
* S减decr,如果S小于0,阻塞当前线程
*/publicsynchronizedvoidp(int decr) {
s -= decr;
if (s < 0) {
try {
wait();
}catch (InterruptedException e) {
// ...
}
}
}
/**
* V原语,原子操作
* <p>
* S加incr,如果S小于等于0,唤醒一个等待中的线程
*/publicsynchronizedvoidv(int incr) {
s += incr;
if (s <= 0) {
notify();
}
}
}