JavaTM 2 Platform
Standard Ed. 6

java.util.concurrent
類別 Semaphore

java.lang.Object
  繼承者 java.util.concurrent.Semaphore
所有已實作的介面:
Serializable

public class Semaphore
extends Object
implements Serializable

一個計數信號量。從概念上講,信號量維護了一個許可集。如有必要,在許可可用前會阻塞每一個 acquire(),然後再獲取該許可。每個 release() 添加一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可物件,Semaphore 只對可用許可的號碼進行計數,並採取相應的行動。

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() 時無法保持同步鎖,因為這會阻止將項返回到池中。信號量封裝所需的同步,以限制對池的存取,這同維持該池本身一致性所需的同步是分開的。

將信號量初始化為 1,使得它在使用時最多只有一個可用的許可,從而可用作一個相互排斥的鎖。這通常也稱為二進制信號量,因為它只能有兩種狀態:一個可用的許可,或零個可用的許可。按此方式使用時,二進制信號量具有某種屬性(與很多 Lock 實作不同),即可以由執行緒釋放“鎖”,而不是由所有者(因為信號量沒有所有權的概念)。在某些專門的上下文(如死鎖恢復)中這會很有用。

此類別的建構子可選地接受一個公平 參數。當設置為 false 時,此類別不對執行緒獲取許可的順序做任何保證。特別地,闖入 是允許的,也就是說可以在已經等待的執行緒前為調用 acquire() 的執行緒分派一個許可,從邏輯上說,就是新執行緒將自己置於等待執行緒佇列的頭部。當公平設置為 true 時,信號量保證對於任何調用獲取方法的執行緒而言,都按照處理它們調用這些方法的順序(即先進先出;FIFO)來選擇執行緒、獲得許可。注意,FIFO 排序必然應用到這些方法內的指定內部執行點。所以,可能某個執行緒先於另一個執行緒調用了 acquire,但是卻在該執行緒之後到達排序點,並且從方法返回時也類似。還要注意,非同步的 tryAcquire 方法不使用公平設置,而是使用任意可用的許可。

通常,應該將用於控制資源存取的信號量初始化為公平的,以確保所有執行緒都可存取資源。為其他的種類別的同步控制使用信號量時,非公平排序的吞吐量優勢通常要比公平考慮更為重要。

此類別還提供便捷的方法來同時 acquire釋放多個許可。小心,在未將公平設置為 true 時使用這些方法會增加不確定延期的風險。

記憶體一致性效果:執行緒中調用「釋放」方法(比如 release())之前的操作 happen-before 另一執行緒中緊跟在成功的「獲取」方法(比如 acquire())之後的操作。

從以下版本開始:
1.5
另請參見:
序列化表格

建構子摘要
Semaphore(int permits)
          創建具有給定的許可數和非公平的公平設置的 Semaphore
Semaphore(int permits, boolean fair)
          創建具有給定的許可數和給定的公平設置的 Semaphore
 
方法摘要
 void acquire()
          從此信號量獲取一個許可,在提供一個許可前一直將執行緒阻塞,否則執行緒被中斷
 void acquire(int permits)
          從此信號量獲取給定數目的許可,在提供這些許可前一直將執行緒阻塞,或者執行緒已被中斷
 void acquireUninterruptibly()
          從此信號量中獲取許可,在有可用的許可前將其阻塞。
 void acquireUninterruptibly(int permits)
          從此信號量獲取給定數目的許可,在提供這些許可前一直將執行緒阻塞。
 int availablePermits()
          返回此信號量中當前可用的許可數。
 int drainPermits()
          獲取並返回立即可用的所有許可。
protected  Collection<Thread> getQueuedThreads()
          返回一個 collection,包含可能等待獲取的執行緒。
 int getQueueLength()
          返回正在等待獲取的執行緒的估計數目。
 boolean hasQueuedThreads()
          查詢是否有執行緒正在等待獲取。
 boolean isFair()
          如果此信號量的公平設置為 true,則返回 true
protected  void reducePermits(int reduction)
          根據指定的縮減量減小可用許可的數目。
 void release()
          釋放一個許可,將其返回給信號量。
 void release(int permits)
          釋放給定數目的許可,將其返回到信號量。
 String toString()
          返回標識此信號量的字元串,以及信號量的狀態。
 boolean tryAcquire()
          僅在調用時此信號量存在一個可用許可,才從信號量獲取許可。
 boolean tryAcquire(int permits)
          僅在調用時此信號量中有給定數目的許可時,才從此信號量中獲取這些許可。
 boolean tryAcquire(int permits, long timeout, TimeUnit unit)
          如果在給定的等待時間內此信號量有可用的所有許可,並且當前執行緒未被中斷,則從此信號量獲取給定數目的許可。
 boolean tryAcquire(long timeout, TimeUnit unit)
          如果在給定的等待時間內,此信號量有可用的許可並且當前執行緒未被中斷,則從此信號量獲取一個許可。
 
從類別 java.lang.Object 繼承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

建構子詳細資訊

Semaphore

public Semaphore(int permits)
創建具有給定的許可數和非公平的公平設置的 Semaphore

參數:
permits - 初始的可用許可數目。此值可能為負數,在這種情況下,必須在授予任何獲取前進行釋放。

Semaphore

public Semaphore(int permits,
                 boolean fair)
創建具有給定的許可數和給定的公平設置的 Semaphore

參數:
permits - 初始的可用許可數目。此值可能為負數,在這種情況下,必須在授予任何獲取前進行釋放。
fair - 如果此信號量保證在爭用時按先進先出的順序授予許可,則為 true;否則為 false
方法詳細資訊

acquire

public void acquire()
             throws InterruptedException
從此信號量獲取一個許可,在提供一個許可前一直將執行緒阻塞,否則執行緒被中斷

獲取一個許可(如果提供了一個)並立即返回,將可用的許可數減 1。

如果沒有可用的許可,則在發生以下兩種情況之一前,禁止將當前執行緒用於執行緒安排目的並使其處於休眠狀態:

如果當前執行緒:

則拋出 InterruptedException,並且清除當前執行緒的已中斷狀態。

拋出:
InterruptedException - 如果當前執行緒被中斷

acquireUninterruptibly

public void acquireUninterruptibly()
從此信號量中獲取許可,在有可用的許可前將其阻塞。

獲取一個許可(如果提供了一個)並立即返回,將可用的允許數減 1。

如果沒有可用的許可,則在其他某些執行緒調用此信號量的 release() 方法,並且當前執行緒是下一個要被分派許可的執行緒前,禁止當前執行緒用於執行緒安排目的並使其處於休眠狀態。

如果當前執行緒在等待許可時被中斷,那麼它將繼續等待,但是與沒有發生中斷,其將接收允許的時間相比,為該執行緒分派許可的時間可能改變。當執行緒確實從此方法返回後,將設置其中斷狀態。


tryAcquire

public boolean tryAcquire()
僅在調用時此信號量存在一個可用許可,才從信號量獲取許可。

獲取一個許可(如果提供了一個)並立即返回,其值為 true,將可用的許可數減 1。

如果沒有可用的許可,則此方法立即返回並且值為 false

即使已將此信號量設置為使用公平排序策略,但是調用 tryAcquire() 立即獲取許可(如果有一個可用),而不管當前是否有正在等待的執行緒。在某些情況下,此“闖入”行為可能很有用,即使它會打破公平性也如此。如果希望遵守公平設置,則使用 tryAcquire(0, TimeUnit.SECONDS) ,它幾乎是等效的(它也檢測中斷)。

返回:
如果獲取了許可,則返回 true;否則返回 false

tryAcquire

public boolean tryAcquire(long timeout,
                          TimeUnit unit)
                   throws InterruptedException
如果在給定的等待時間內,此信號量有可用的許可並且當前執行緒未被中斷,則從此信號量獲取一個許可。

獲取一個許可(如果提供了一個)並立即返回,其值為 true,將可用的許可數減 1。

如果沒有可用的允許,則在發生以下三種情況之一前,禁止將當前執行緒用於執行緒安排目的並使其處於休眠狀態:

如果獲取了許可,則返回值為 true

如果當前執行緒:

則拋出 InterruptedException,並且清除當前執行緒的已中斷狀態。

如果超出了指定的等待時間,則返回值為 false。如果該時間小於等於 0,則方法根本不等待。

參數:
timeout - 等待許可的最多時間
unit - timeout 參數的時間單位
返回:
如果獲取了許可,則返回 true;如果獲取許可前超出了等待時間,則返回 false
拋出:
InterruptedException - 如果當前執行緒是已中斷的

release

public void release()
釋放一個許可,將其返回給信號量。

釋放一個許可,將可用的許可數增加 1。如果任意執行緒試圖獲取許可,則選中一個執行緒並將剛剛釋放的許可給予它。然後針對執行緒安排目的啟用(或再啟用)該執行緒。

不要求釋放許可的執行緒必須通過調用 acquire() 來獲取許可。通過應用程序中的程式約定來建立信號量的正確用法。


acquire

public void acquire(int permits)
             throws InterruptedException
從此信號量獲取給定數目的許可,在提供這些許可前一直將執行緒阻塞,或者執行緒已被中斷

獲取給定數目的許可(如果提供了)並立即返回,將可用的許可數減去給定的量。

如果沒有足夠的可用許可,則在發生以下兩種情況之一前,禁止將當前執行緒用於執行緒安排目的並使其處於休眠狀態:

如果當前執行緒:

則拋出 InterruptedException,並且清除當前執行緒的已中斷狀態。任何原本應該分派給此執行緒的許可將被分派給其他試圖獲取許可的執行緒,就好像已通過調用 release() 而使許可可用一樣。

參數:
permits - 要獲取的許可數
拋出:
InterruptedException - 如果當前執行緒已被中斷
IllegalArgumentException - 如果 permits 為負

acquireUninterruptibly

public void acquireUninterruptibly(int permits)
從此信號量獲取給定數目的許可,在提供這些許可前一直將執行緒阻塞。

獲取給定數目的許可(如果提供了)並立即返回,將可用的許可數減去給定的量。

如果沒有足夠的可用許可,則在其他某些執行緒調用此信號量的某個釋放方法,當前執行緒是下一個要被分派許可的執行緒,並且可用的許可數目滿足此請求前,禁止當前執行緒用於執行緒安排目的並使其處於休眠狀態。

如果當前的執行緒在等待許可時被中斷,則它會繼續等待並且它在佇列中的位置不受影響。當執行緒確實從此方法返回後,將其設置為中斷狀態。

參數:
permits - 要獲取的許可數
拋出:
IllegalArgumentException - 如果 permits 為負

tryAcquire

public boolean tryAcquire(int permits)
僅在調用時此信號量中有給定數目的許可時,才從此信號量中獲取這些許可。

獲取給定數目的許可(如果提供了)並立即返回,其值為 true,將可用的許可數減去給定的量。

如果沒有足夠的可用許可,則此方法立即返回,其值為 false,並且不改變可用的許可數。

即使已將此信號量設置為使用公平排序策略,但是調用 tryAcquire 立即獲取許可(如果有一個可用),而不管當前是否有正在等待的執行緒。在某些情況下,此“闖入”行為可能很有用,即使它會打破公平性也如此。如果希望遵守公平設置,則使用 tryAcquire(permits, 0, TimeUnit.SECONDS) ,它幾乎是等效的(它也檢測中斷)。

參數:
permits - 要獲取的許可數
返回:
如果獲取了許可,則返回 true;否則返回 false
拋出:
IllegalArgumentException - 如果 permits 為負

tryAcquire

public boolean tryAcquire(int permits,
                          long timeout,
                          TimeUnit unit)
                   throws InterruptedException
如果在給定的等待時間內此信號量有可用的所有許可,並且當前執行緒未被中斷,則從此信號量獲取給定數目的許可。

獲取給定數目的許可(如果提供了)並立即返回,其值為 true,將可用的許可數減去給定的量。

如果沒有足夠的可用許可,則在發生以下三種情況之一前,禁止將當前執行緒用於執行緒安排目的並使其處於休眠狀態:

如果獲取了許可,則返回值為 true

如果當前執行緒:

則拋出 InterruptedException,並且清除當前執行緒的已中斷狀態。任何原本應該分派給此執行緒的許可將被分派給其他試圖獲取許可的執行緒,就好像已通過調用 release() 而使許可可用一樣。

如果超出了指定的等待時間,則返回值為 false。如果該時間小於等於 0,則方法根本不等待。任何原本應該分派給此執行緒的許可將被分派給其他試圖獲取許可的執行緒,就好像已通過調用 release() 而使許可可用一樣。

參數:
permits - 要獲取的許可數
timeout - 等待許可的最多時間
unit - timeout 參數的時間單位
返回:
如果獲取了許可,則返回 true;如果獲取所有許可前超出了等待時間,則返回 false
拋出:
InterruptedException - 如果當前執行緒是已中斷的
IllegalArgumentException - 如果 permits 為負

release

public void release(int permits)
釋放給定數目的許可,將其返回到信號量。

釋放給定數目的許可,將可用的許可數增加該量。如果任意執行緒試圖獲取許可,則選中某個執行緒並將剛剛釋放的許可給予該執行緒。如果可用許可的數目滿足該執行緒的請求,則針對執行緒安排目的啟用(或再啟用)該執行緒;否則在有足夠的可用許可前執行緒將一直等待。如果滿足此執行緒的請求後仍有可用的許可,則依次將這些許可分派給試圖獲取許可的其他執行緒。

不要求釋放許可的執行緒必須通過調用獲取來獲取該許可。通過應用程序中的程式約定來建立信號量的正確用法。

參數:
permits - 要釋放的許可數
拋出:
IllegalArgumentException - 如果 permits 為負

availablePermits

public int availablePermits()
返回此信號量中當前可用的許可數。

此方法通常用於除錯和測試目的。

返回:
此信號量中的可用許可數

drainPermits

public int drainPermits()
獲取並返回立即可用的所有許可。

返回:
獲取的許可數

reducePermits

protected void reducePermits(int reduction)
根據指定的縮減量減小可用許可的數目。此方法在使用信號量來追蹤那些變為不可用資源的子類別中很有用。此方法不同於 acquire,在許可變為可用的過程中,它不會阻塞等待。

參數:
reduction - 要移除的許可數
拋出:
IllegalArgumentException - 如果 reduction 是負數

isFair

public boolean isFair()
如果此信號量的公平設置為 true,則返回 true

返回:
如果此信號量的公平設置為 true,則返回 true

hasQueuedThreads

public final boolean hasQueuedThreads()
查詢是否有執行緒正在等待獲取。注意,因為同時可能發生取消,所以返回 true 並不保證有其他執行緒等待獲取許可。此方法主要用於監視系統狀態。

返回:
如果可能有其他執行緒正在等待獲取鎖,則返回 true

getQueueLength

public final int getQueueLength()
返回正在等待獲取的執行緒的估計數目。該值僅是估計的數字,因為在此方法遍歷內部資料結構的同時,執行緒的數目可能動態地變化。此方法用於監視系統狀態,不用於同步控制。

返回:
正在等待此鎖的執行緒的估計數目

getQueuedThreads

protected Collection<Thread> getQueuedThreads()
返回一個 collection,包含可能等待獲取的執行緒。因為在建構此結果的同時實際的執行緒 set 可能動態地變化,所以返回的 collection 僅是盡力的估計值。所返回 collection 中的元素沒有特定的順序。此方法用於加快子類別的建構速度,提供更多的監視設施。

返回:
執行緒 collection

toString

public String toString()
返回標識此信號量的字元串,以及信號量的狀態。括號中的狀態包括 String 型別的 "Permits =",後跟許可數。

覆寫:
類別 Object 中的 toString
返回:
標識此信號量的字元串,以及信號量的狀態

JavaTM 2 Platform
Standard Ed. 6

提交錯誤或意見

版權所有 2008 Sun Microsystems, Inc. 保留所有權利。請遵守GNU General Public License, version 2 only