天天看點

Semaphore(Java 信号量)

這篇文章介紹的 java.util.concurrent.Semaphore類是一個計數信号量。它有兩個主要的方法:

  • acquire()
  • release()

計數信号量在初始化的時候指定一定數量的許可N,意味着在允許N個線程通路自願。當線程調用 acquire() ,一個許可被占用,沒有許可的時候就等待;而 release() 意味着釋放一個許可,Semaphore是Java的一個簡單的計數器。

兩種用法

  • 保護重要部分的代碼最多被N個線程通路。
  • 單個信号量的Semaphore對象可以實作互斥鎖的功能,并且可以是由一個線程獲得了“鎖”,再由另一個線程釋放“鎖”,這可應用于死鎖恢複的一些場合。

代碼執行個體

public class SemaphoreTest {

    private static final int THREAD_COUNT = ; // 線程數量設定30個

    private static ExecutorService threadPool = Executors
            .newFixedThreadPool(THREAD_COUNT);

    private static Semaphore s = new Semaphore(); // 允許十個線程并發

    public static void main(String[] args) {
        for (int i = ; i < THREAD_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        s.acquire();
                        System.out.println("save data");
                        s.release();
                    } catch (InterruptedException e) {
                    }
                }
            });
        }

        threadPool.shutdown();
    }
}
           

在代碼中,雖然有30個線程在執行,但是隻允許10個并發的執行。Semaphore的構造方法Semaphore(int permits) 接受一個整型的數字,表示可用的許可證數量。Semaphore(10)表示允許10個線程擷取許可證,也就是最大并發數是10。Semaphore的用法也很簡單,首先線程使用Semaphore的acquire()擷取一個許可證,使用完之後調用release()歸還許可證。還可以用tryAcquire()方法嘗試擷取許可證。

其他方法

  • int availablePermits() :傳回此信号量中目前可用的許可證數。
  • int getQueueLength():傳回正在等待擷取許可證的線程數。
  • boolean hasQueuedThreads() :是否有線程正在等待擷取許可證。
  • void reducePermits(int reduction) :減少reduction個許可證。是個protected方法。
  • Collection getQueuedThreads() :傳回所有等待擷取許可證的線程集合。是個protected方法。

公平性

Semaphore不保證第一個調用acquire() 方法的線程就是第一個獲得許可通路資源的線程。但是如果需要強制制造公平,Semaphore 提供了下面的構造方法,這種方法會有損Semaphore 的并發性,除非是必要使用公平性,否則不建議使用它。

Semaphore semaphore = new Semaphore(, true);