Most visited

Recently visited

Added in API level 1

Semaphore

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方法不符合公平性设置,但会采用任何可用的许可证。

通常,用于控制资源访问的信号量应该被初始化为公平的,以确保没有线程被饿死而不能访问资源。 当使用信号量进行其他类型的同步控制时,非公平排序的吞吐量优势往往超过公平性考虑。

此课程同时提供acquirerelease多种许可的便捷方法。 这些方法通常比循环更高效。 但是,他们没有建立任何优惠顺序。 例如,如果线程A调用s.acquire(3 )并且线程B调用s.acquire(2) ,并且有两个许可证可用,则不能保证线程B将获得它们,除非其获取先到达并且信号量s处于公平模式。

内存一致性影响:在调用诸如 release() happen-before类的“释放”方法之前,线程中的操作在另一个线程中成功获取方法(如 acquire()之后执行。

Summary

Public constructors

Semaphore(int permits)

使用给定数量的许可证和非公平公平设置创建 Semaphore

Semaphore(int permits, boolean fair)

用给定数量的许可证和给定的公平设置创建一个 Semaphore

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,则返回 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

Public constructors

Semaphore

Added in API level 1
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

Added in API level 1
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

Public methods

acquire

Added in API level 1
void acquire ()

从此信号量获取许可证,直到有一个可用,或线程为 interrupted

获取许可证(如果有许可证并立即返回),将可用许可证的数量减少一个。

如果没有许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到发生以下两件事之一:

  • Some other thread invokes the release() method for this semaphore and the current thread is next to be assigned a permit; or
  • Some other thread interrupts the current thread.

如果当前线程:

  • has its interrupted status set on entry to this method; or
  • is interrupted while waiting for a permit,
then InterruptedException is thrown and the current thread's interrupted status is cleared.

Throws
InterruptedException if the current thread is interrupted

acquire

Added in API level 1
void acquire (int permits)

从这个信号量中获取给定数量的许可,阻塞直到所有可用,或线程为 interrupted

获取给定数量的许可证(如果可用),并立即返回,将可用许可证的数量减少给定数量。 这种方法与循环for (int i = 0; i < permits; ++i) acquire();具有相同的效果,不同之处在于它一次自动获取许可证:

如果没有足够的许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到发生以下两件事之一:

  • Some other thread invokes one of the 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
  • Some other thread interrupts the current thread.

如果当前线程:

  • has its interrupted status set on entry to this method; or
  • is interrupted while waiting for a permit,
then 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

acquireUninterruptibly

Added in API level 1
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

acquireUninterruptibly

Added in API level 1
void acquireUninterruptibly ()

从此信号量获取许可证,直到有一个可用。

获取许可证(如果有许可证并立即返回),将可用许可证的数量减少一个。

如果没有可用的许可证,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到某个其他线程为该信号量调用方法 release() ,并且当前线程接下来被分配许可证。

如果当前线程在等待许可证时等待interrupted ,那么它将继续等待,但线程被分配许可证的时间可能会改变,而不是中断发生时允许的时间。 当线程从该方法返回时,其中断状态将被设置。

availablePermits

Added in API level 1
int availablePermits ()

返回此信号量中当前可用的许可证数量。

此方法通常用于调试和测试目的。

Returns
int the number of permits available in this semaphore

drainPermits

Added in API level 1
int drainPermits ()

获取并返回所有立即可用的许可证。

Returns
int the number of permits acquired

getQueueLength

Added in API level 1
int getQueueLength ()

返回等待获取的线程数的估计值。 该值仅为估计值,因为在此方法遍历内部数据结构时,线程数可能会动态变化。 此方法设计用于监视系统状态,而不是用于同步控制。

Returns
int the estimated number of threads waiting for this lock

hasQueuedThreads

Added in API level 1
boolean hasQueuedThreads ()

查询是否有线程正在等待获取。 请注意,因为取消可能随时发生, true退货并不能保证任何其他线程都会获得。 此方法主要用于监视系统状态。

Returns
boolean true if there may be other threads waiting to acquire the lock

isFair

Added in API level 1
boolean isFair ()

如果此信号量具有公平性,则返回 true

Returns
boolean true if this semaphore has fairness set true

release

Added in API level 1
void release (int permits)

释放给定数量的许可证,并将它们返回到信号量。

发放给定数量的许可证,增加可用许可证数量。 如果有线程试图获得许可证,则选择一个线程并给予刚刚发布的许可证。 如果可用许可证的数量满足该线程的请求,那么为了线程调度目的,该线程被(重新)启用; 否则线程将等待,直到有足够的许可证可用。 如果在线程的请求得到满足后仍有许可证可用,那么这些许可证将依次分配给尝试获取许可证的其他线程。

没有要求释放许可的线程必须通过调用acquire获得许可。 正确使用信号量是通过编程约定在应用程序中建立的。

Parameters
permits int: the number of permits to release
Throws
IllegalArgumentException if permits is negative

release

Added in API level 1
void release ()

发布许可证,将其返回给信号量。

颁发许可证,将可用许可证数量增加一个。 如果有线程试图获得许可证,则选择一个并获得刚刚发布的许可证。 为了线程调度目的,该线程被(重新)启用。

没有要求释放许可的线程必须通过调用acquire()获得许可。 正确使用信号量是通过编程约定在应用程序中建立的。

toString

Added in API level 1
String toString ()

返回标识此信号量的字符串及其状态。 括号中的状态包括字符串"Permits ="后面跟着许可证的数量。

Returns
String a string identifying this semaphore, as well as its state

tryAcquire

Added in API level 1
boolean tryAcquire (long timeout, 
                TimeUnit unit)

如果在给定的等待时间内可用,并且当前线程尚未达到 interrupted ,则从此信号量获取许可证。

获取许可证(如果有许可证并立即返回),值为 true ,将可用许可证的数量减少一个。

如果没有许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到发生以下三种情况之一:

  • Some other thread invokes the release() method for this semaphore and the current thread is next to be assigned a permit; or
  • Some other thread interrupts the current thread; or
  • The specified waiting time elapses.

如果获得许可证,则返回值 true

如果当前线程:

  • has its interrupted status set on entry to this method; or
  • is interrupted while waiting to acquire a permit,
then 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

tryAcquire

Added in API level 1
boolean tryAcquire (int permits, 
                long timeout, 
                TimeUnit unit)

如果在给定的等待时间内全部变为可用并且当前线程尚未 interrupted ,则从该信号量获取给定数量的许可证。

获取给定数量的许可证(如果它们可用并立即返回),值为 true ,将可用许可证的数量减少给定数量。

如果没有足够的许可证可用,则当前线程因为线程调度目的而被禁用,并且处于休眠状态,直到发生以下三件事之一:

  • Some other thread invokes one of the 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
  • Some other thread interrupts the current thread; or
  • The specified waiting time elapses.

如果获得许可证,则返回值 true

如果当前线程:

  • has its interrupted status set on entry to this method; or
  • is interrupted while waiting to acquire the permits,
then 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

tryAcquire

Added in API level 1
boolean tryAcquire ()

只有在调用时可用的情况下才能从此信号中获取许可。

获得许可证(如果有许可证并立即返回),值为 true ,将可用许可证的数量减少一个。

如果没有许可证可用,则此方法将立即返回值 false

即使该信号量已被设置为使用公平的订购策略,如果可用的话,对tryAcquire()的调用立即获得许可证,而不管其他线程当前是否在等待。 这种“bar”“行为在某些情况下可能会有用,即使它违背公平。 如果要遵守公平性设置,则使用tryAcquire(0, TimeUnit.SECONDS) ,它几乎相当(它也检测到中断)。

Returns
boolean true if a permit was acquired and false otherwise

tryAcquire

Added in API level 1
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

Protected methods

getQueuedThreads

Added in API level 1
Collection<Thread> getQueuedThreads ()

返回包含可能正在等待获取的线程的集合。 因为实际的一组线程可能会在构造这个结果时动态地改变,所以返回的集合只是一个尽力而为的估计。 返回的集合的元素没有特定的顺序。 该方法旨在促进提供更广泛监测设施的子类的构建。

Returns
Collection<Thread> the collection of threads

reducePermits

Added in API level 1
void reducePermits (int reduction)

按指定的减少量缩减可用许可的数量。 此方法在使用信号量来追踪变得不可用的资源的子类中非常有用。 该方法不同于acquire处在于它不会阻止等待许可证变得可用。

Parameters
reduction int: the number of permits to remove
Throws
IllegalArgumentException if reduction is negative

Hooray!