Semaphore分為單值和多值兩種,前者只能被一個線程獲得,後者可以被若干個線程獲得。
Semaphore實現的功能就類似廁所有5個坑,假如有10個人要上廁所,那麼同時只能有多少個人去上廁所呢?同時只能有5個人能夠占用,當5個人中 的任何一個人讓開後,其中等待的另外5個人中又有一個人可以占用了。另外等待的5個人中可以是隨機獲得優先機會,也可以是按照先來後到的順序獲得機會,這取決於構造Semaphore對象時傳入的參數選項。單個信號量的Semaphore對象可以實現互斥鎖的功能,並且可以是由一個線程獲得了“鎖”,再由另一個線程釋放“鎖”,這可應用於死鎖恢復的一些場合。
再以一個停車場運作為例。為了簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛不受阻礙的進入,然後放下車攔,剩下的車則必須在入口等待,此後來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知後,打開車攔,放入一輛,如果又離開兩輛,則又可以放入兩輛,如此往復。
在這個停車場系統中,車位是公共資源,每輛車好比一個線程,看門人起的就是信號量的作用。
更進一步,信號量的特性如下:信號量是一個非負整數(車位數),所有通過它的線程(車輛)都會將該整數減一(使用資源),當該整數值為零時,所有試圖通過它的線程都將處於等待狀態。在信號量上我們定義兩種操作: Wait(等待) 和 Release(釋放)。 當一個線程調用Wait(等待)操作時,它要麼通過然後將信號量減一,要麼一直等下去,直到信號量大於一或超時。Release(釋放)實際上是在信號量上執行加操作,對應於車輛離開停車場,該操作之所以叫做“釋放”是因為加操作實際上是釋放了由信號量守護的資源。
Semaphore(int permits, boolean fair) //創建具有給定的許可數和給定的公平設置的Semaphore。
還可以設置該信號量是否采用公平模式,如果以公平方式執行,則線程將會按到達的順序(FIFO)執行,如果是非公平,則可以後請求的有可能排在隊列的頭部。
Semaphore可以控制某個資源可被同時訪問的個數,通過 acquire() 獲取一個許可,如果沒有就等待,而 release() 釋放一個許可。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class SemaphoreTest { public static void main(String[] args) { // 線程池 ExecutorService exec = Executors.newCachedThreadPool(); // 只能5個線程同時訪問 final Semaphore semp = new Semaphore(5); // 模擬20個客戶端訪問 for (int index = 0; index < 50; index++) { final int NO = index; Runnable run = new Runnable() { public void run() { try { // 獲取許可 semp.acquire(); System.out.println("Accessing: " + NO); Thread.sleep((long) (Math.random() * 10000)); // 訪問完後,釋放 semp.release(); //availablePermits()指的是當前信號燈庫中有多少個可以被使用 System.out.println("-----------------" + semp.availablePermits()); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.execute(run); } // 退出線程池 exec.shutdown(); } }
Accessing: 0 Accessing: 1 Accessing: 2 Accessing: 4 Accessing: 6 Accessing: 8 -----------------0 -----------------1 Accessing: 3 -----------------1 Accessing: 5 Accessing: 9 -----------------0 -----------------1 Accessing: 7 Accessing: 10 -----------------0 -----------------1 Accessing: 11 -----------------1 Accessing: 12 -----------------1 Accessing: 13 Accessing: 14 -----------------0 -----------------1 Accessing: 15 -----------------0 Accessing: 16 -----------------1 Accessing: 17 -----------------1 Accessing: 18 -----------------1 Accessing: 19 -----------------0 Accessing: 20 Accessing: 21 -----------------0 Accessing: 22 -----------------0 -----------------1 Accessing: 23 -----------------1 Accessing: 24 -----------------0 Accessing: 25 Accessing: 26 -----------------0 -----------------1 Accessing: 27 -----------------1 Accessing: 28 -----------------1 Accessing: 29 Accessing: 30 -----------------0 -----------------1 Accessing: 31 -----------------1 Accessing: 32 -----------------1 Accessing: 33 -----------------1 Accessing: 34 Accessing: 35 -----------------0 -----------------1 Accessing: 36 -----------------1 Accessing: 37 -----------------1 Accessing: 38 -----------------1 Accessing: 39 -----------------1 Accessing: 40 Accessing: 41 -----------------0 -----------------1 Accessing: 42 Accessing: 43 -----------------0 Accessing: 44 -----------------0 -----------------1 Accessing: 45 -----------------1 Accessing: 46 -----------------1 Accessing: 47 -----------------1 Accessing: 48 -----------------1 Accessing: 49 -----------------1 -----------------2 -----------------3 -----------------4 -----------------5