public class Semaphore
extends Object
implements Serializable
java.lang.Object | |
↳ | java.util.concurrent.Semaphore |
计数信号量。 从概念上讲,信号量维护一套许可证。 如有必要,每个acquire()
阻止,直到许可证可用,然后将其acquire()
。 每个release()
添加一个许可证,可能会释放阻止的收单机构。 但是,没有使用实际的许可证对象; 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;
}
}
在获得物品之前,每个线程都必须从信号中获取许可证,以确保物品可供使用。 当线程完成了该项目后,它将返回到池中,并且许可证返回到信号量,允许另一个线程获取该项目。 请注意,如果acquire()
,则不会保持同步锁定,因为这会阻止将项目返回到池中。 信号量封装了限制对池的访问所需的同步,与维护池本身一致性所需的任何同步分开进行。
一个信号量被初始化为一个,并且被使用,使得它只有最多一个可用的许可证,可以用作互斥锁。 这通常被称为二进制信号量 ,因为它只有两种状态:一种允许可用,或者零允许可用。 当以这种方式使用时,二进制信号量具有属性(与许多Lock
实现不同),“锁定”可以由所有者之外的线程释放(因为信号量没有所有权概念)。 这在一些特定的上下文中很有用,例如死锁恢复。
此类的构造函数可以接受公平参数。 当设置为false时,该类不保证线程获取许可的顺序。 特别是, 闯入是允许的,也就是说,一个线程调用acquire()
可以提前已经等待线程分配的许可证-在等待线程队列的头部逻辑新的线程将自己。 当公平性设置为真时,信号量保证调用任何acquire
方法的线程被选中,以按照它们调用这些方法的顺序获得许可(先进先出; FIFO)。 请注意,FIFO排序必须适用于这些方法中的特定内部执行点。 所以,一个线程可能在另一个线程之前调用acquire
,但是到达另一个线程之后的排序点,并且类似地从该方法返回。 另请注意,不tryAcquire
方法不符合公平性设置,但会采用任何可用的许可证。
通常,用于控制资源访问的信号量应该被初始化为公平的,以确保没有线程被饿死而不能访问资源。 当使用信号量进行其他类型的同步控制时,非公平排序的吞吐量优势往往超过公平性考虑。
此课程同时提供acquire
和release
多种许可的便捷方法。 这些方法通常比循环更高效。 但是,他们没有建立任何优惠顺序。 例如,如果线程A调用s.acquire(3
)并且线程B调用s.acquire(2)
,并且有两个许可证可用,则不能保证线程B将获得它们,除非其获取先到达并且信号量s
处于公平模式。
内存一致性影响:在调用诸如 release()
happen-before之类的“释放”方法之前,线程中的操作在另一个线程中成功获取方法(如 acquire()
之后执行。
Public constructors |
|
---|---|
Semaphore(int permits) 使用给定数量的许可证和非公平公平设置创建 |
|
Semaphore(int permits, boolean fair) 用给定数量的许可证和给定的公平设置创建一个 |
Public methods |
|
---|---|
void |
acquire() 从这个信号中获取许可,阻塞直到有一个可用,或线程为 interrupted 。 |
void |
acquire(int permits) 从这个信号量中获取给定数量的许可,阻塞直到所有可用,或线程为 interrupted 。 |
void |
acquireUninterruptibly(int permits) 从这个信号量中获取给定数量的许可,阻塞直到所有可用。 |
void |
acquireUninterruptibly() 从此信号量获取许可证,直到有一个可用。 |
int |
availablePermits() 返回此信号量中当前可用的许可证数量。 |
int |
drainPermits() 获取并返回所有立即可用的许可证。 |
final int |
getQueueLength() 返回等待获取的线程数的估计值。 |
final boolean |
hasQueuedThreads() 查询是否有线程正在等待获取。 |
boolean |
isFair() 如果此信号量的公平性设置为true,则返回 |
void |
release(int permits) 释放给定数量的许可证,并将它们返回到信号量。 |
void |
release() 发布许可证,将其返回给信号量。 |
String |
toString() 返回标识此信号量的字符串及其状态。 |
boolean |
tryAcquire(long timeout, TimeUnit unit) 如果在给定的等待时间内有效并且当前线程尚未达到 interrupted ,则从此信号量获取许可证。 |
boolean |
tryAcquire(int permits, long timeout, TimeUnit unit) 如果在给定的等待时间内全部变得可用,并且当前线程不是 interrupted ,则从此信号量获取给定数量的许可证。 |
boolean |
tryAcquire() 只有在调用时可用的情况下才能从此信号中获取许可。 |
boolean |
tryAcquire(int permits) 只有在调用时所有许可都可用的情况下,才从该信号中获取给定数量的许可。 |
Protected methods |
|
---|---|
Collection<Thread> |
getQueuedThreads() 返回包含可能正在等待获取的线程的集合。 |
void |
reducePermits(int reduction) 按指定的减少量缩减可用许可的数量。 |
Inherited methods |
|
---|---|
From class java.lang.Object
|
Semaphore (int permits)
使用给定数量的许可证和非公平公平设置创建 Semaphore
。
Parameters | |
---|---|
permits |
int : the initial number of permits available. This value may be negative, in which case releases must occur before any acquires will be granted. |
Semaphore (int permits, boolean fair)
使用给定的许可证数量和给定的公平性设置创建 Semaphore
。
Parameters | |
---|---|
permits |
int : the initial number of permits available. This value may be negative, in which case releases must occur before any acquires will be granted. |
fair |
boolean : true if this semaphore will guarantee first-in first-out granting of permits under contention, else false |
void acquire ()
从此信号量获取许可证,直到有一个可用,或线程为 interrupted 。
获取许可证(如果有许可证并立即返回),将可用许可证的数量减少一个。
如果没有许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到发生以下两件事之一:
release()
method for this semaphore and the current thread is next to be assigned a permit; or 如果当前线程:
InterruptedException
is thrown and the current thread's interrupted status is cleared.
Throws | |
---|---|
InterruptedException |
if the current thread is interrupted |
void acquire (int permits)
从这个信号量中获取给定数量的许可,阻塞直到所有可用,或线程为 interrupted 。
获取给定数量的许可证(如果可用),并立即返回,将可用许可证的数量减少给定数量。 这种方法与循环for (int i = 0; i < permits; ++i) acquire();
具有相同的效果,不同之处在于它一次自动获取许可证:
如果没有足够的许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到发生以下两件事之一:
release
methods for this semaphore and the current thread is next to be assigned permits and the number of available permits satisfies this request; or 如果当前线程:
InterruptedException
is thrown and the current thread's interrupted status is cleared. Any permits that were to be assigned to this thread are instead assigned to other threads trying to acquire permits, as if permits had been made available by a call to
release()
.
Parameters | |
---|---|
permits |
int : the number of permits to acquire |
Throws | |
---|---|
InterruptedException |
if the current thread is interrupted |
IllegalArgumentException |
if permits is negative |
void acquireUninterruptibly (int permits)
从这个信号量中获取给定数量的许可,阻塞直到所有可用。
获取给定数量的许可证(如果可用),并立即返回,将可用许可证的数量减少给定数量。 这种方法与循环for (int i = 0; i < permits; ++i) acquireUninterruptibly();
具有相同的效果,只是它一次自动获取许可证:
如果没有足够的许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到某个其他线程为该信号量调用其中一个 release
方法,并且当前线程接下来将被分配许可证并且可用许可证的数量满足此请求。
如果当前线程在等待许可时为interrupted ,那么它将继续等待并且它在队列中的位置不受影响。 当线程从该方法返回时,其中断状态将被设置。
Parameters | |
---|---|
permits |
int : the number of permits to acquire |
Throws | |
---|---|
IllegalArgumentException |
if permits is negative |
void acquireUninterruptibly ()
从此信号量获取许可证,直到有一个可用。
获取许可证(如果有许可证并立即返回),将可用许可证的数量减少一个。
如果没有可用的许可证,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到某个其他线程为该信号量调用方法 release()
,并且当前线程接下来被分配许可证。
如果当前线程在等待许可证时等待interrupted ,那么它将继续等待,但线程被分配许可证的时间可能会改变,而不是中断发生时允许的时间。 当线程从该方法返回时,其中断状态将被设置。
int availablePermits ()
返回此信号量中当前可用的许可证数量。
此方法通常用于调试和测试目的。
Returns | |
---|---|
int |
the number of permits available in this semaphore |
int drainPermits ()
获取并返回所有立即可用的许可证。
Returns | |
---|---|
int |
the number of permits acquired |
int getQueueLength ()
返回等待获取的线程数的估计值。 该值仅为估计值,因为在此方法遍历内部数据结构时,线程数可能会动态变化。 此方法设计用于监视系统状态,而不是用于同步控制。
Returns | |
---|---|
int |
the estimated number of threads waiting for this lock |
boolean hasQueuedThreads ()
查询是否有线程正在等待获取。 请注意,因为取消可能随时发生, true
退货并不能保证任何其他线程都会获得。 此方法主要用于监视系统状态。
Returns | |
---|---|
boolean |
true if there may be other threads waiting to acquire the lock |
boolean isFair ()
如果此信号量具有公平性,则返回 true
。
Returns | |
---|---|
boolean |
true if this semaphore has fairness set true |
void release (int permits)
释放给定数量的许可证,并将它们返回到信号量。
发放给定数量的许可证,增加可用许可证数量。 如果有线程试图获得许可证,则选择一个线程并给予刚刚发布的许可证。 如果可用许可证的数量满足该线程的请求,那么为了线程调度目的,该线程被(重新)启用; 否则线程将等待,直到有足够的许可证可用。 如果在线程的请求得到满足后仍有许可证可用,那么这些许可证将依次分配给尝试获取许可证的其他线程。
没有要求释放许可的线程必须通过调用acquire
获得许可。 正确使用信号量是通过编程约定在应用程序中建立的。
Parameters | |
---|---|
permits |
int : the number of permits to release |
Throws | |
---|---|
IllegalArgumentException |
if permits is negative |
void release ()
发布许可证,将其返回给信号量。
颁发许可证,将可用许可证数量增加一个。 如果有线程试图获得许可证,则选择一个并获得刚刚发布的许可证。 为了线程调度目的,该线程被(重新)启用。
没有要求释放许可的线程必须通过调用acquire()
获得许可。 正确使用信号量是通过编程约定在应用程序中建立的。
String toString ()
返回标识此信号量的字符串及其状态。 括号中的状态包括字符串"Permits ="
后面跟着许可证的数量。
Returns | |
---|---|
String |
a string identifying this semaphore, as well as its state |
boolean tryAcquire (long timeout, TimeUnit unit)
如果在给定的等待时间内可用,并且当前线程尚未达到 interrupted ,则从此信号量获取许可证。
获取许可证(如果有许可证并立即返回),值为 true
,将可用许可证的数量减少一个。
如果没有许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到发生以下三种情况之一:
release()
method for this semaphore and the current thread is next to be assigned a permit; or 如果获得许可证,则返回值 true
。
如果当前线程:
InterruptedException
is thrown and the current thread's interrupted status is cleared.
如果经过了指定的等待时间,则返回值false
。 如果时间小于或等于零,该方法将不会等待。
Parameters | |
---|---|
timeout |
long : the maximum time to wait for a permit |
unit |
TimeUnit : the time unit of the timeout argument |
Returns | |
---|---|
boolean |
true if a permit was acquired and false if the waiting time elapsed before a permit was acquired |
Throws | |
---|---|
InterruptedException |
if the current thread is interrupted |
boolean tryAcquire (int permits, long timeout, TimeUnit unit)
如果在给定的等待时间内全部变为可用并且当前线程尚未 interrupted ,则从该信号量获取给定数量的许可证。
获取给定数量的许可证(如果它们可用并立即返回),值为 true
,将可用许可证的数量减少给定数量。
如果没有足够的许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到发生以下三件事之一:
release
methods for this semaphore and the current thread is next to be assigned permits and the number of available permits satisfies this request; or 如果获得许可证,则返回值 true
。
如果当前线程:
InterruptedException
is thrown and the current thread's interrupted status is cleared. Any permits that were to be assigned to this thread, are instead assigned to other threads trying to acquire permits, as if the permits had been made available by a call to
release()
.
如果经过指定的等待时间,则返回值false
。 如果时间小于或等于零,该方法将不会等待。 任何被分配给这个线程的许可都被分配给其他尝试获取许可的线程,就好像许可已经通过调用release()
来release()
。
Parameters | |
---|---|
permits |
int : the number of permits to acquire |
timeout |
long : the maximum time to wait for the permits |
unit |
TimeUnit : the time unit of the timeout argument |
Returns | |
---|---|
boolean |
true if all permits were acquired and false if the waiting time elapsed before all permits were acquired |
Throws | |
---|---|
InterruptedException |
if the current thread is interrupted |
IllegalArgumentException |
if permits is negative |
boolean tryAcquire ()
只有在调用时可用的情况下才能从此信号中获取许可。
获得许可证(如果有许可证并立即返回),值为 true
,将可用许可证的数量减少一个。
如果没有许可证可用,则此方法将立即返回值 false
。
即使该信号量已被设置为使用公平的订购策略,如果可用的话,对tryAcquire()
的调用将立即获得许可证,而不管其他线程当前是否在等待。 这种“bar”“行为在某些情况下可能会有用,即使它违背公平。 如果要遵守公平性设置,则使用tryAcquire(0, TimeUnit.SECONDS)
,它几乎相当(它也检测到中断)。
Returns | |
---|---|
boolean |
true if a permit was acquired and false otherwise |
boolean tryAcquire (int permits)
只有在调用时所有许可都可用的情况下,才从该信号中获取给定数量的许可。
获取给定数量的许可证(如果可用),并立即返回,值为 true
,将可用许可证的数量减少给定数量。
如果没有足够的许可证,则此方法将立即返回值 false
并且可用许可证的数量不变。
即使这个信号量已经被设置为使用公平的订购策略,如果可用的话,对tryAcquire
的调用将立即获得许可证,无论其他线程当前是否在等待。 这种“bar”“行为在某些情况下可能会有用,即使它违背公平。 如果要遵守公平性设置,则使用几乎相同的tryAcquire(permits, 0, TimeUnit.SECONDS)
(它也会检测到中断)。
Parameters | |
---|---|
permits |
int : the number of permits to acquire |
Returns | |
---|---|
boolean |
true if the permits were acquired and false otherwise |
Throws | |
---|---|
IllegalArgumentException |
if permits is negative |
Collection<Thread> getQueuedThreads ()
返回包含可能正在等待获取的线程的集合。 因为实际的一组线程可能会在构造这个结果时动态地改变,所以返回的集合只是一个尽力而为的估计。 返回的集合的元素没有特定的顺序。 该方法旨在促进提供更广泛监测设施的子类的构建。
Returns | |
---|---|
Collection<Thread> |
the collection of threads |
void reducePermits (int reduction)
按指定的减少量缩减可用许可的数量。 此方法在使用信号量来追踪变得不可用的资源的子类中非常有用。 该方法不同于acquire
处在于它不会阻止等待许可证变得可用。
Parameters | |
---|---|
reduction |
int : the number of permits to remove |
Throws | |
---|---|
IllegalArgumentException |
if reduction is negative |