一、Semaphore 简介
Semaphore 是一个计数的信号量,维护了一定数量的许可,没有获取到许可的线程将会等待。内部持有了两个AQS的子类,分别是公平锁和非公平锁,二者主要的区别在于公平锁的获取会判断是否存在等待获取锁的线程,若有会直接放弃锁的争夺。Semaphore可以用来控制某个方法的并发数量,增加边界等。
关于AQS同步器,可以看另一篇博客 AQS详解
二、Semaphore源码分析
Semaphore内部用AQS的state表示许可的个数,当state等于0时,线程获取共享锁失败,state大于0时,线程获取到许可(共享锁),并将state减1,归还时将state加1。
非公平锁获取锁,剩余许可小于0时,共享锁获取失败进入AQS的队列;
剩余许可大于0时,CAS将许可减1(acquires 为1)。
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
公平锁获取锁之前要判断有没有等待的线程:hasQueuedPredecessors(),如果有直接返回-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;
}
}
三、Semaphore实战
1.指定大小的池子 pool,代码来自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();
}
// Not a particularly efficient data structure; just for demo
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;
}
}}