1. 程式人生 > >同步工具類三:計數訊號量(java.util.concurrent.Semaphore)

同步工具類三:計數訊號量(java.util.concurrent.Semaphore)

計數訊號量用來控制同時訪問某個特定資源的運算元或同時執行某個指定操作的數量

A counting semaphore.Conceptually, a semaphore maintains a set of permits. Each acquire blocks if necessary until a permit is available, and then takes it. Each release adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.

從概念上來說,Semaphore中維護了一組許可,許可的數量在建構函式中指定。acquire方法將獲取一個可用的許可,如果沒有可用的許可,該方法會被阻塞,直到Semaphore中有可用的許可。release方法釋放一個許可,如果此時存在阻塞中的acqure方法,將釋放一個阻塞中的acquire

事實上,Semaphore中只維護可用請求數量,並不包含實際的許可物件

在初始化Semaphore時可以設定其公平性,如果為公平Semaphore,則按照請求時間獲得許可,即先發送的請求先獲得許可,如果為非公平Semaphore,則先發送的請求未必先獲得許可,這有助於提高程式的吞吐量,但是有可能導致某些請求始終獲取不到許可(tryAcquire方法不使用公平性設定)

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;

public class Test implements Runnable{
    private static CountDownLatch latch = new CountDownLatch(1);
    private static Semaphore semaphore = new Semaphore(2, true);

    public void run(){
        try {
            latch.await();
            this.work();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void work() throws InterruptedException{
        // 如果等待acquire的執行緒過多,則終止後續執行緒的執行
        if(semaphore.getQueueLength() > 2){
            System.out.println("Too many thread waiting to acquire" + Thread.currentThread().getName());
            return;
        }

        semaphore.acquire();
        System.out.println("acquired by " + Thread.currentThread().getName());
        Thread.sleep(1*1000);
        semaphore.release();
    }

    public static void main(String[] args) throws Exception{
        for(int i = 0 ; i < 10 ; i++){
            Thread t = new Thread(new Test());
            t.start();
        }
        //保證所有執行緒同時執行
        latch.countDown();
    }
}

執行結果如下:

acquired by Thread-9
Too many thread waiting to acquireThread-7
Too many thread waiting to acquireThread-3
Too many thread waiting to acquireThread-5
Too many thread waiting to acquireThread-6
acquired by Thread-1
Too many thread waiting to acquireThread-8
acquired by Thread-2
acquired by Thread-0
acquired by Thread-4