转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72857243
Semaphore是信号量,它的作用是控制多个允许。
打个比方,一个博物馆有容纳1000人的能力(Semaphore的允许是1000),假如1500人同时来参馆,只有1000人能获得允许入馆(获得锁),其余的500则需排队(阻塞),直到馆内的人离开(释放锁)才能放人入馆。
1 如何使用
public class SemaphoreDemo {
public static void main(String[] args) {
for (int i = 0; i < 4; i++) {
new Thread(new SemaphoreTest()).start();
}
}
static class SemaphoreTest implements Runnable{
public static Semaphore semaphore = new Semaphore(2, true);
@Override
public void run() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread() + " getting semaphore");
Thread.sleep(1000);
System.out.println(Thread.currentThread() + " realsing semaphore");
semaphore.release();
} catch (Exception e) {
}
}
}
}
程序输出
Thread[Thread-1,5,main] getting semaphore
Thread[Thread-0,5,main] getting semaphore
Thread[Thread-0,5,main] realsing semaphore
Thread[Thread-1,5,main] realsing semaphore
Thread[Thread-3,5,main] getting semaphore
Thread[Thread-2,5,main] getting semaphore
Thread[Thread-2,5,main] realsing semaphore
Thread[Thread-3,5,main] realsing semaphore
2 源码分析
Semaphore的内部实现也是基于AQS类的,不了解的可以参考AbstractQueuedSynchronizer同步器一文。
Semaphore
与ReetrantLock
一样有公平锁与非公平锁,ReetrantLock
可以看成是Semaphore
许可为1的特例,在实现中,Semaphore
中的state
代表可用的许可,在ReetrantLock
中,state
大于0代表线程重入的次数
2.1 非公平锁
(1)获取许可
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
remaining表示请求许可后的许可剩余值,如果
- remaining < 0,许可不足,挂起线程,并且添加线程至排队队列
- remaining > 0,自旋尝试更新state值,更新成功获得许可
从代码可以看到,当一个线程申请许可时,无需判断是否有线程在排队队列中,体现非公平性
(2)释放许可
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
自旋采用CAS算法更新state状态
2.2 公平锁
(1)获取许可
protected int tryAcquireShared(int acquires) {
for (;;) {
// 先判断排队队列中是否为空
if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
公平锁的机制比非公平锁多了判断排队队列是否为空,如果有其他线程在排队队列中,则该线程也需转入排队队列,体现公平性。
3 总结
- Semaphore是不可重入的,同一线程多次获取Semaphore是会消耗许可的,例如一个Semaphore的许可为2,同一线程调用了3次acquire函数,该线程会被阻塞
参考
http://www.jianshu.com/p/0090341c6b80
转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72857243