1. 程式人生 > >java.util.Concurrent.Semaphore 原始碼

java.util.Concurrent.Semaphore 原始碼

類圖

原始碼

package java.util.concurrent;

import java.util.Collection;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class Semaphore implements java.io.Serializable {
    private static final long serialVersionUID = -3222578661600680210L;//版本號
   
    private final Sync sync;//內部類

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;//版本號

        //構造器,將允許執行的數量設為permits
        Sync(int permits) {
            setState(permits);
        }

        //根據state得到允許執行的數量
        final int getPermits() {
            return getState();
        }

        //不公平共享鎖獲取(狀態減去acquires)
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();//獲取當前狀態
                int remaining = available - acquires;//狀態值減acquires
                //若狀態值小於0則不更新,直接返回-1,表示獲取鎖失敗
                //狀態值大於等於0,更新當前狀態值,返回大於等於0則表示成功
                if (remaining < 0 || compareAndSetState(available, remaining))
                    return remaining;//只有此處才能退出迴圈
            }
        }

        //公平鎖釋放(狀態增加acquires)
        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();//獲取當前狀態
                int next = current + releases;//狀態值加acquires
                if (next < current)//若狀態值有誤,丟擲異常
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))//只有修改成功,才能退出迴圈
                    return true;
            }
        }

        //允許執行數減少reductions
        final void reducePermits(int reductions) {
            for (;;) {
                int current = getState();//得到當前允許執行數
                int next = current - reductions;//將允許執行數減去reductions
                if (next > current)//若發現允許執行數發生了變化,則丟擲異常
                    throw new Error("Permit count underflow");
                if (compareAndSetState(current, next))//只有修改成功,才能退出迴圈
                    return;
            }
        }

        //返回允許執行的數,並將允許執行數置為0(“耗盡”所有剩餘共享資源)
        final int drainPermits() {
            for (;;) {
                int current = getState();//得到當前狀態值
                if (current == 0 || compareAndSetState(current, 0))//只有允許修改成功或剩餘為0,才能退出迴圈
                    return current;//返回當前狀態值
            }
        }
    }

    //不公平策略
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;//版本號

        //和公平策略構造器相同
        NonfairSync(int permits) {//呼叫sync的構造器初始化允許執行數
            super(permits);
        }

        //直接呼叫nonfairTryAcquireShared,嘗試獲取不公平的共享鎖
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

    //公平策略
    static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;//版本號

        //和不公平策略構造器相同
        FairSync(int permits) {//呼叫sync的構造器初始化允許執行數
            super(permits);
        }

        //嘗試獲取公平的共享鎖。和不公平的共享鎖不同的關鍵方法
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())//存在前繼等待節點則直接返回
                    return -1;
                int available = getState();//得到當前狀態值
                int remaining = available - acquires;//當前狀態減去acquires
                if (remaining < 0 || compareAndSetState(available, remaining))
                    return remaining;//修改成功
            }
        }
    }

    //permits:一次性允許執行的執行緒數
    //一個引數構造預設使用不公平策略.
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    //permits:一次性允許執行的執行緒數
    //fair:是否使用公平策略.
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

    //可響應中斷的獲取共享鎖1個(公平和不公平)
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    //不支援響應中斷的獲取共享鎖1個(公平和不公平)
    public void acquireUninterruptibly() {
        sync.acquireShared(1);
    }

    //不公平的嘗試獲取共享鎖1個(不支援中斷)
    public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;//大於等於0,則獲取成功
    }

    //支援中斷在指定時間內獲取共享鎖1個
    public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

    //計數值增加1
    public void release() {
        sync.releaseShared(1);//計數值增加1
    }

/******************不使用時,每次呼叫一次性減1;**************************/
/******************傳入permits時,每次呼叫一次性減permits;***************/

    //可響應中斷的獲取共享鎖(公平和不公平)permits個
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();//permits小於0,則丟擲非法引數異常
        sync.acquireSharedInterruptibly(permits);
    }

    //不支援響應中斷的獲取共享鎖permits個(公平和不公平)
    public void acquireUninterruptibly(int permits) {
        if (permits < 0) throw new IllegalArgumentException();//permits小於0,則丟擲非法引數異常
        sync.acquireShared(permits);
    }

    //不公平的嘗試獲取共享鎖permits個(不支援中斷)
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();//permits小於0,則丟擲非法引數異常
        return sync.nonfairTryAcquireShared(permits) >= 0;//大於等於0,則獲取成功
    }

    //支援中斷在指定時間內獲取共享鎖permits個
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();//permits小於0,則丟擲非法引數異常
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }

    //增加指定數目permits(增加計數值permits)
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();//permits小於0,則丟擲非法引數異常
        sync.releaseShared(permits);//增加計數值
    }

    //得到當前執行的數
    public int availablePermits() {
        return sync.getPermits();
    }

    //返回允許執行的數,並將允許執行數置為0(“耗盡”所有剩餘共享資源)
    public int drainPermits() {
        return sync.drainPermits();
    }

    //將允許執行數減少指定數目reduction.(“縮減”剩餘共享資源)
    protected void reducePermits(int reduction) {
        if (reduction < 0) throw new IllegalArgumentException();//reduction小於0,則丟擲非法引數異常
        sync.reducePermits(reduction);
    }

    //根據判斷sync 是否為FairSync型別,返回是否為公平鎖
    public boolean isFair() {
        return sync instanceof FairSync;
    }

    //返回佇列中是否存在等待狀態的節點
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    //得到佇列元素的總數
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    //得到佇列中的執行緒集合
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    //得到字串表示
    public String toString() {
        return super.toString() + "[Permits = " + sync.getPermits() + "]";
    }
}

類 Semaphore

    一個計數訊號量,訊號量維護了一個許可集。

    在許可可用前會阻塞每一個呼叫acquire()的執行緒。

    已獲取共享鎖的執行緒,執行 release() 新增一個許可,從而可能釋放一個正在阻塞的獲取者。

    Semaphore 通常用於限制可以訪問某些資源(物理或邏輯的)的執行緒數目。

 

構造方法摘要

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

     構造方法可選地接受一個公平 引數。當設定為 false 時,此類不對執行緒獲取許可的順序做任何保證。

    特別地,闖入 是允許的,也就是說可以在已經等待的執行緒前為呼叫 acquire() 的執行緒分配一個許可,從邏輯上說,就是新執行緒將自己置於等待執行緒佇列的頭部。

    當公平設定為 true 時,訊號量保證對於任何呼叫獲取方法的執行緒而言,都按照處理它們呼叫這些方法的順序(即先進先出;FIFO)來選擇執行緒、獲得許可。

    非同步的 tryAcquire 方法不使用公平設定,而是使用任意可用的許可。

    通常,應該將用於控制資源訪問的訊號量初始化為公平的,以確保所有執行緒都可訪問資源。

    為其他的種類的同步控制使用訊號量時,非公平排序的吞吐量優勢通常要比公平考慮更為重要。

 

方法摘要

 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) 
          如果在給定的等待時間內,此訊號量有可用的許可並且當前執行緒未被中斷,則從此訊號量獲取一個許可。

 

 

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。

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

  • 某些其他執行緒呼叫此訊號量的 release() 方法,並且當前執行緒是下一個要被分配許可的執行緒;或者
  • 其他某些執行緒中斷當前執行緒。

    如果當前執行緒:

  • 被此方法將其已中斷狀態設定為 on ;或者
  • 在等待許可時被中斷

    則丟擲 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。

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

  • 其他某些執行緒呼叫此訊號量的 release() 方法並且當前執行緒是下一個被分配許可的執行緒;或者
  • 其他某些執行緒中斷當前執行緒;或者
  • 已超出指定的等待時間。

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

    如果當前執行緒:

  • 被此方法將其已中斷狀態設定為 on ;或者
  • 在等待獲取許可的同時被中斷

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

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

    引數:

    timeout - 等待許可的最多時間

    unit - timeout 引數的時間單位

    返回:

        如果獲取了許可,則返回 true;如果獲取許可前超出了等待時間,則返回 false

    丟擲:

    InterruptedException - 如果當前執行緒是已中斷的

 

release

public void release()

    釋放一個許可,將其返回給訊號量。

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

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

 

acquire

public void acquire(int permits) throws InterruptedException

    從此訊號量獲取給定數目的許可,在提供這些許可前一直將執行緒阻塞,或者執行緒已被 中斷

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

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

  • 其他某些執行緒呼叫此訊號量的某個釋放方法,當前執行緒是下一個被分配允許的執行緒並且可用許可的數目滿足此請求;或者
  • 其他某些執行緒中斷當前執行緒。

    如果當前執行緒:

  • 被此方法將其已中斷狀態設定為 on ;或者
  • 在等待許可時被中斷

    則丟擲 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

    如果當前執行緒:

  • 被此方法將其已中斷狀態設定為 on ;或者
  • 在等待獲取允許的同時被中斷

    則丟擲 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

    返回:

        標識此訊號量的字串,以及訊號量的狀態

 

使用例項:

  • 1.銀行有3個櫃檯,每個櫃檯只能每次服務1個客戶:
package com.thread;

import java.util.concurrent.Semaphore;

public class SemaphoreDemo implements Runnable{
    private Semaphore smp = new Semaphore(3);

    @Override
    public void run() {
        try {
            System.out.println("Thread " + Thread.currentThread().getName() + " start");
            smp.acquire();
            System.out.println("Thread " + Thread.currentThread().getName() + " is working");
            Thread.sleep(1000);
            smp.release();
            System.out.println("Thread " + Thread.currentThread().getName() + " is over");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        SemaphoreDemo semaphoreDemo = new SemaphoreDemo();
        for (int i=1;i<=9;i++){
            new Thread(semaphoreDemo).start();
        }
    }
}

    執行結果:

Thread Thread-0 start
Thread Thread-3 start
Thread Thread-0 is working
Thread Thread-1 start
Thread Thread-2 start
Thread Thread-1 is working
Thread Thread-6 start
Thread Thread-5 start
Thread Thread-3 is working
Thread Thread-4 start
Thread Thread-7 start
Thread Thread-8 start
Thread Thread-0 is over
Thread Thread-2 is working

Thread Thread-3 is over
Thread Thread-5 is working
Thread Thread-1 is over
Thread Thread-6 is working
Thread Thread-2 is over
Thread Thread-5 is over
Thread Thread-8 is working
Thread Thread-4 is working
Thread Thread-7 is working
Thread Thread-6 is over

Thread Thread-8 is over
Thread Thread-7 is over
Thread Thread-4 is over
 

     紅色部分說明:只能一次性執行3個執行緒,必須要等待某一個執行緒執行 release() 之後,才能喚醒等待的某一個執行緒繼續執行。

    青色部分說明:由於列印語句的執行可能會滯後,因此此處的執行結果不能說明 Semaphore 設計有誤,所以執行結果只能作為參考。

  • 2.銀行有3個櫃檯,一次性服務3個,服務完畢3個,才能繼續執行下3個客戶;若一次性服務所需櫃檯數超過實際櫃檯數,則無法繼續進行執行;只要所需櫃檯數小於等於實際櫃檯數,均可以正常執行下去:
package com.thread;

import java.util.concurrent.Semaphore;

public class SemaphoreDemo implements Runnable{
    private Semaphore smp = new Semaphore(3);

    @Override
    public void run() {
        try {
            System.out.println("Thread " + Thread.currentThread().getName() + " start");
            smp.acquire(3);
            System.out.println("Thread " + Thread.currentThread().getName() + " is working");
            Thread.sleep(1000);
            smp.release(3);
            System.out.println("Thread " + Thread.currentThread().getName() + " is over");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        SemaphoreDemo semaphoreDemo = new SemaphoreDemo();
        for (int i=1;i<=9;i++){
            new Thread(semaphoreDemo).start();
        }
    }
}

    執行結果:

Thread Thread-0 start
Thread Thread-3 start
Thread Thread-4 start
Thread Thread-6 start
Thread Thread-1 start
Thread Thread-7 start
Thread Thread-8 start
Thread Thread-0 is working
Thread Thread-5 start
Thread Thread-2 start
Thread Thread-0 is over
Thread Thread-3 is working
Thread Thread-3 is over
Thread Thread-4 is working
Thread Thread-4 is over
Thread Thread-6 is working
Thread Thread-6 is over
Thread Thread-1 is working
Thread Thread-1 is over
Thread Thread-7 is working
Thread Thread-7 is over
Thread Thread-8 is working
Thread Thread-8 is over
Thread Thread-5 is working
Thread Thread-5 is over
Thread Thread-2 is working
Thread Thread-2 is over

    由於需要一次性獲取3個,所以只有一個執行緒執行完畢,才能執行下一個執行緒。