源码
package java.util.concurrent;
public class Semaphore implements java.io.Serializable {
private static final long serialVersionUID = -3222578661600680210L;
/** All mechanics via AbstractQueuedSynchronizer subclass */
private final Sync sync;
/**
* 信号量的同步实现。使用AQS状态代表许可。分为公平和非公平版本。
*/
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;
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");
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;
}
}
}
/**
* 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;
}
}
}
/**
* 创建具有给定数量的许可和不公平设置的{@code Semaphore}。
*/
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
/**
* 创建具有给定数量的许可和给定的公平性的{@code Semaphore}。
*/
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
/**
* 从此信号灯获取许可,直到一个可用的信号被阻塞,或者线程被{@linkplain Thread#interrupt interrupted}阻塞。
* 如果有许可证,则获取许可证并立即返回,从而将可用许可证的数量减少一个。
* 如果没有可用的许可,则当前线程将出于线程调度目的而被禁用,并处于休眠状态,直到发生以下两种情况之一:另一个线程为此信号量调用{@link
* 允许;或某个其他线程{@linkplain Thread#interrupt interrupts}当前线程。
* 如果当前线程:在进入此方法时设置了其中断状态;或者在等待许可时{@linkplain Thread#interrupt被中断},则抛出{@link InterruptedException}并清除当前线程的中断状态。
*/
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* 从此信号量获取许可,直到可用为止。
* 如果有许可证,则获取许可证并立即返回,从而将可用许可证的数量减少一个。
* 如果没有可用的许可,则当前线程将出于线程调度目的而被禁用,并处于休眠状态,直到某个其他线程为此信号量调用{@link
* 如果当前线程在等待许可时被{@linkplain Thread#interrupt interrupted中断},则它将继续等待,但是与没有许可的情况相比,分配该线程许可的时间可能会有所变化。
* 发生中断。
* 当线程确实从该方法返回时,将设置其中断状态。
*
*/
public void acquireUninterruptibly() {
sync.acquireShared(1);
}
/**
* 仅在调用时可用时,才从此信号量获取许可。
* 如果许可证可用,则获取许可证并立即返回,其值为{@code true},从而将可用许可证数量减少一个。
* 如果没有可用的许可,则此方法将立即返回值{@code false}。
* 即使已将此信号量设置为使用公平的排序策略,如果可用,则对{@code tryAcquire()}的调用将立即获得许可,无论当前是否正在等待其他线程。
* 即使破坏公平性,这种“讨价还价”的行为在某些情况下还是有用的。
* 如果要遵守公平性设置,请使用几乎等效的{@link
*/
public boolean tryAcquire() {
return sync.nonfairTryAcquireShared(1) >= 0;
}
/**
* 如果在给定的等待时间内有一个可用信号并且当前线程尚未{@linkplain Thread#interrupt interrupted},则从此信号量获取许可。
* 如果许可证可用,则获取许可证并立即返回,其值为{@code true},从而将可用许可证数量减少一个。
* 如果没有可用的许可,则当前线程将出于线程调度目的而被禁用,并处于休眠状态,直到发生以下三种情况之一:另一个线程为此信号量调用{@link
* 允许;或其他某个线程{@linkplain Thread#interrupt interrupts}当前线程;或经过了指定的等待时间。
* 如果获得许可,则返回值{@code true}。
* 如果当前线程:在进入此方法时设置了其中断状态;或在等待获取许可时{@linkplain线程
* 如果经过了指定的等待时间,则返回值{@code false}。
* 如果时间小于或等于零,则该方法将根本不等待。
*/
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
/**
* 释放许可证,将其返回到信号灯。
* 发放许可证,将可用许可证数量增加一个。
* 如果有任何线程试图获取许可,则选择一个线程并授予刚刚释放的许可。
* 出于线程调度目的而启用(重新)该线程。
* 不要求释放许可证的线程必须通过调用{@link
* 通过在应用程序中编程约定,可以正确使用信号量。
*
*/
public void release() {
sync.releaseShared(1);
}
/**
* 从该信号量获取给定数量的许可,阻塞直到所有许可都可用,或者线程{@linkplain Thread#interrupt interrupted}。
* 如果有可用许可证,则获取给定数量的许可证,然后立即返回,从而将可用许可证的数量减少给定数量。
* 如果没有足够的许可,则当前线程将出于线程调度目的而被禁用,并处于休眠状态,直到发生以下两种情况之一:另一个线程为此信号量调用{@link
* 如果当前线程:在进入此方法时设置了其中断状态;或者在等待许可时{@linkplain Thread#interrupt被中断},则抛出{@link InterruptedException}并清除当前线程的中断状态。
* 相反,将要分配给该线程的所有许可都分配给其他尝试获取许可的线程,就像通过调用{@link
*
*/
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
/**
* 从此信号量获取给定数量的许可,直到所有条件都可用为止都将阻塞。
* 如果有可用许可证,则获取给定数量的许可证,然后立即返回,从而将可用许可证的数量减少给定数量。
* 如果没有足够的许可,则当前线程将出于线程调度目的而被禁用,并处于休眠状态,直到某个其他线程为此信号量调用{@link
* 如果当前线程在等待许可时{@linkplain线程
* 当线程确实从该方法返回时,将设置其中断状态。
*
*/
public void acquireUninterruptibly(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireShared(permits);
}
/**
* 仅在调用时所有可用的条件下,从此信号量获取给定数量的许可。
* 如果有可用许可证,则获取给定数量的许可证,并立即返回,其值为{@code true},从而将可用许可证的数量减少给定数量。
* 如果没有足够的许可证,则此方法将立即返回{@code false},并且可用许可证的数量不变。
* 即使已将此信号量设置为使用公平的排序策略,如果有可用的线程,无论是否正在等待其他线程,对{@code tryAcquire}的调用都将立即获得许可。
* 即使破坏公平性,这种“讨价还价”的行为在某些情况下还是有用的。
* 如果要遵守公平性设置,请使用几乎等效的{@link
*
*/
public boolean tryAcquire(int permits) {
if (permits < 0) throw new IllegalArgumentException();
return sync.nonfairTryAcquireShared(permits) >= 0;
}
/**
* 如果所有信号都在给定的等待时间内可用,并且当前线程尚未{@linkplain线程
* 如果有可用许可证,则获取给定数量的许可证,然后立即返回,其值为{@code true},从而将可用许可证的数量减少给定数量。
* 如果没有足够的许可,则当前线程将出于线程调度目的而被禁用,并处于休眠状态,直到发生以下三种情况之一:其他一些线程为此信号量调用{@link
* 如果获得许可,则返回值{@code true}。
* 如果当前线程:在进入此方法时设置了其中断状态;或在等待获取许可的过程中被{@linkplain Thread#interrupt interrupted中断},则抛出{@link InterruptedException}并清除当前线程的中断状态。
* 相反,将要分配给该线程的所有许可,都分配给其他尝试获取许可的线程,就像通过调用{@link
* 如果经过了指定的等待时间,则返回值{@code false}。
* 如果时间小于或等于零,则该方法将根本不等待。
* 相反,将要分配给该线程的所有许可,都分配给其他尝试获取许可的线程,就像通过调用{@link
*
*/
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
}
/**
* @param permits the number of permits to release
* @throws IllegalArgumentException if {@code permits} is negative
* 释放给定数量的许可证,将其返回到信号灯。
* 释放给定数量的许可证,将可用许可证的数量增加该数量。
* 如果有任何线程试图获取许可,则选择一个线程并给出刚刚释放的许可。
* 如果可用许可的数量满足该线程的请求,则出于线程调度目的而(重新)启用该线程。
* 否则,线程将等待,直到有足够的许可可用为止。
* 如果在满足该线程的请求之后仍然有可用的许可,则将这些许可依次分配给其他尝试获取许可的线程。
* 无需要求释放许可的线程必须通过调用{@link Semaphore#acquire acquisition}获得许可。
* 通过在应用程序中编程约定,可以正确使用信号量。
*
*/
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
/**
* 返回此信号量中当前可用的许可数量。此方法通常用于调试和测试目的。
*/
public int availablePermits() {
return sync.getPermits();
}
/**
* 获取并返回所有立即可用的许可证。
*/
public int drainPermits() {
return sync.drainPermits();
}
/**
* 通过指示的减少量缩小可用许可证的数量。此方法在使用信号量跟踪变得不可用的资源的子类中很有用。
* 此方法与{@code acquisition}的不同之处在于,它不会阻止等待许可证可用。
*/
protected void reducePermits(int reduction) {
if (reduction < 0) throw new IllegalArgumentException();
sync.reducePermits(reduction);
}
/**
* Returns {@code true} if this semaphore has fairness set true.
*
* @return {@code true} if this semaphore has fairness set true
*/
public boolean isFair() {
return sync instanceof FairSync;
}
/**
* 查询是否有任何线程正在等待获取。
* 请注意,由于取消可能随时发生,因此{@code true}返回值不能保证任何其他线程都可以获取。
* 此方法主要设计用于监视系统状态。
*
* @return {@code true} if there may be other threads waiting to
* acquire the lock
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* 返回等待获取的线程数的估计值。
* 该值只是一个估计值,因为在此方法遍历内部数据结构时,线程数可能会动态变化。
* 此方法设计用于监视系统状态,而不用于同步控制。
*
* @return the estimated number of threads waiting for this lock
*/
public final int getQueueLength() {
return sync.getQueueLength();
}
/**
* 返回一个包含可能正在等待获取的线程的集合。
* 因为实际的线程集在构造此结果时可能会动态变化,所以返回的集合只是尽力而为的估计。
* 返回的集合的元素没有特定的顺序。
* 设计此方法是为了便于构造子类,以提供更广泛的监视功能。
*
*/
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
/**
* 返回标识此信号量及其状态的字符串。括号中的状态包括字符串{@code“ Permits =”},后跟许可数量。
* @return a string identifying this semaphore, as well as its state
*/
public String toString() {
return super.toString() + "[Permits = " + sync.getPermits() + "]";
}
}