一、概述
Semaphore信号量,主要功能是限制能够运行的线程量,指定固定数量的许可,只有获取许可的线程可以运行,若没有许可获取则阻塞,直到获取许可。
二、源码分析
1、构造函数
/**
* 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);
}
/**
* @param fair {@code true} 保证竞争先进先出
*/
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
Semaphore中同步器Sync继承AQS实现AQS中的共享模式tryReleaseShared(int releases)方法,同步器只实现了共享锁的释放,并未实现锁的获取tryAcquireShared(int arg)方法;
Semaphore中公平和非公平是通过它的两个私有的静态内部类FairSync、NonFairSync实现,他们通过继承Sync并实现共享锁的获取tryAcquireShared(int arg)方法;
非公平实现:
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
// 只是实现了AQS中的共享锁的获取
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
公平实现:
static final class FairSync extends Sync {
private static final long serialVersionUID = 2014338818796000944L;
FairSync(int permits) {
super(permits);
}
// 只是实现了AQS中的共享锁的获取
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;
}
}
}
2、void acquire()
这个方法是从信号量获取一个许可,在获取到许可,或线程中断之前,当前线程阻塞;获取许可后立即返回并将许可数减一
/**
* 如果没有许可可用,则会休眠知道发生以下两种情况
* 1、其他调用release方法释放许可,并且当前线程获取到许可
* 2、其他线程中断了当前线程
* 1)当前线程在进入这个方法时设置了中断标志位
* 2)等待许可时发生了中断,则抛出中断异常
*/
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
这个方法是直接调用AQS的acquireSharedInterruptibly(int ard)方法;
方法实现原理请查看AQS源码:
/**
* 首先检测是否中断.中断后抛出异常
* 尝试获取许可,成功退出;失败则进入AQS队列,直至成功获取或中断
*/
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 尝试获取锁,返回剩余共享锁的数量;小于0则加入同步队列,自旋
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
tryAcquireShared(arg)则会调用Semaphore中两个同步器的实现方法;
如果获取失败则加入队列等待唤醒;
非公平模式的实现
非公平实现都是首先查看是否有可获取的许可,如果有则获取成功,没有则进队列等待;利用此可以提高并发量,但可能导致某些线程长时间获取不到许可,造成线程‘饿死’。
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
直接调用其父类Sync中非公平共享获取
final int nonfairTryAcquireShared(int acquires) {
// 自旋直到无许可或者状态位赋值成功
for (;;) {
int available = getState();
int remaining = available - acquires;
// 如果小于0则直接返回,否则利用CAS给AQS状态位赋值
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
公平模式的实现
公平与非公平的区别在于始终按照AQS队列FIFO的顺序来的
protected int tryAcquireShared(int acquires) {
//自旋 CAS 实现线程安全
for (;;) {
// 判断是否有前置任务排队
if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
以上两种模式获取失败后都会调用doAcquireSharedInterruptibly(int arg);自旋等待获取锁 。源码解析请看AQS解析。
3、void release()
公平和非公平使用相同的释放
释放许可
public void release() {
sync.releaseShared(1);
}
调用AQS中的releaseShared(int arg)
public final boolean releaseShared(int arg) {
// 调用Sync实现的tryReleaseShared
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
tryReleaseShared(int arg)是父类Sync实现。自旋直到释放成功
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;
}
}
如果释放许可成功,则调用AQS中的doReleaseShared()方法来唤醒AQS队列中等待的线程
源码解析请看AQS解析
这里就是Semaphore的主要源码。