Semaphore是java.util.concurrent下的一个线程同步辅助类.可以维护当前访问自身线程的个数,并提供了同步机制.
Semaphore主要方法:
void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
void release():释放一个许可,将其返回给信号量。
Semaphore通过内部类Sync控制状态的更改,Sync继承了AQS,使用阻塞队列中的节点及state控制线程的并发.
/**
* Synchronization implementation for semaphore. Uses AQS state
* to represent permits. Subclassed into fair and nonfair
* versions.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1192457210091910933L;
// 初始化信号量数量
Sync(int permits) {
setState(permits);
}
// 获取信号量数量
final int getPermits() {
return getState();
}
// 非公平方式尝试获取信号量
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
// 查询当前可用的信号量
int available = getState();
// 是否有可用的信号量
int remaining = available - acquires;
// 小于0没有, 并返回负值. 有则CAS更新有效的剩余信号量数量
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
// 尝试释放信号量
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");
// CAS更新信号量数量
if (compareAndSetState(current, next))
return true;
}
}
// 清除指定数量信号量
final void reducePermits(int reductions) {
for (;;) {
int current = getState();
int next = current - reductions;
if (next > current) // underflow
throw new Error("Permit count underflow");
if (compareAndSetState(current, next))
return;
}
}
// 清除所有剩余信号量
final int drainPermits() {
for (;;) {
int current = getState();
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
}
Sync有公平同步和非公平同步两个子类,
/**
* NonFair version
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
/**
* Fair version
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = 2014338818796000944L;
FairSync(int permits) {
super(permits);
}
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;
}
}
}
默认为非公平同步
/**
* Creates a {@code Semaphore} with the given number of
* permits and nonfair fairness setting.
*
* @param permits the initial number of permits available.
* This value may be negative, in which case releases
* must occur before any acquires will be granted.
*/
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
公平同步需要等前面节点都执行完毕后再执行. 源码在AQS中的hasQueuedPredecessors()中
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
需要注意的getQueueLength()这个方法,获取等待的线程数量,这个数量不是准确的值,是估计的.因为在调用这个方法的同时可能会有其他线程执行,所以等待线程的数量是动态变化的
以上就是Semaphore类里的一些主要点,但是之前说的信号量的释放和获取还是在AQS中.
以下是Node节点的状态,不同的值代表不同的状态
/** 该节点已被取消或中断 */
static final int CANCELLED = 1;
/** 表示当前节点的下一个节点停止进入 */
static final int SIGNAL = -1;
/** 该节点在当前的条件队列中 */
static final int CONDITION = -2;
/**
* 该状态仅用于头节点,确保下节点可以继续获取
*/
static final int PROPAGATE = -3;
// 获取信号量,没有获取到会阻塞
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 没有获取到信号量
if (tryAcquireShared(arg) < 0)
// 根据节点状态 重试获取
doAcquireSharedInterruptibly(arg);
}
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
// 获取上一个节点
final Node p = node.predecessor();
// 是否是头节点
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
// 更新头节点并设置状态
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
// 失败将当前节点取消
cancelAcquire(node);
}
}
// 释放就比较简单
public final boolean releaseShared(int arg) {
// 先将信号量放回去
if (tryReleaseShared(arg)) {
// 更改传播状态
doReleaseShared();
return true;
}
return false;
}
以上只是简单解析主要点,详细实现还需拜读AQS的源码.