Java多執行緒——Semaphore

gary-liu發表於2017-03-14

Semaphore

Semaphore(訊號量)是用來控制同時訪問特定資源的執行緒數量,它通過協調各個執行緒,以保證合理的使用公共資源。

一個計數訊號量。從概念上講,訊號量維護了一個許可集。如有必要,在許可可用前會阻塞每一個 acquire(),然後再獲取該許可。每個 release() 新增一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可物件,Semaphore 只對可用許可的號碼進行計數,並採取相應的行動。拿到訊號量的執行緒可以進入程式碼,否則就等待。通過acquire()和release()獲取和釋放訪問許可。

常用方法

Semaphore(int permits, boolean fair) 可以設定該訊號量是否採用公平模式,如果以公平方式執行,則執行緒將會按到達的順序(FIFO)執行,如果是非公平,則可以後請求的有可能排在佇列的頭部。

int availablePermits() :返回此訊號量中當前可用的許可證數。

int getQueueLength():返回正在等待獲取許可證的執行緒數。

boolean hasQueuedThreads() :是否有執行緒正在等待獲取許可證。

示例

用10個執行緒執行,通過訊號量控制只允許3個併發的執行。

public class SemaphorePractice {

    public void semaphorePrac(){
        Semaphore semaphore = new Semaphore(3);
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for(int i = 0; i < 10; i++){
            executorService.execute(new Runnable(){
                public void run(){
                    try {
                        semaphore.acquire();
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + " is working");
                    semaphore.release();

                }
            });
        }
        executorService.shutdown();
    }

    public static void main(String[] args){
        SemaphorePractice semaphorePractice = new SemaphorePractice();
        semaphorePractice.semaphorePrac();
    }

}

從執行結果中可以看到,因為中間睡眠了2秒,會每兩秒列印三個結果,直到10個執行緒執行完,做到了併發數的控制。

應用場景

Semaphore可以用於做流量控制,控制併發數,特別公用資源有限的應用場景,比如資料庫連線。
Guava中有個RateLimit類使用令牌演算法也可以很好的做到流量控制,而且他們的方法也很類似,有空可以看下他的實現。

參考資料

併發工具類(三)控制併發執行緒數的Semaphore
JAVA多執行緒–訊號量(Semaphore)

相關文章