您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何使用Semaphore”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何使用Semaphore”吧!
姓名:Semaphore
中文名:(計數)信號量
出生日期:JDK 1.5
籍貫:JUC(java.util.concurrent)
用途:Java 中的一個同步器,與 CountDownLatch 和 CyclicBarrier 不同,Semaphore 是用來管理許可證的,線程在調用 acquire() 方法時,如果沒有許可證,那么線程就會阻塞等待,直到有許可證時才能繼續執行。許可證使用 release() 方法來發布(發布一個許可證),調用 acquire() 方法時,如果有證書會減少許可證并繼續執行后面的代碼,如果沒有證書只能阻塞等待許可證,而 Semaphore 在創建時會聲明許可證的最大數量。
我的專業技能就是“管理證書”,使用此技能可以輕松的實現「限流」功能。
比如五一小長假快到了,到那時會有大量的人去各個景區游玩,但是每個景區能容納的人是有限的,比如大西安的大唐芙蓉園,它的日承載量是 6 萬人次,也就是說每天最多能讓 6 萬來這里游玩,但五一的時候會來很多的人,比如突然來了 10 萬人,那這個時候就只能「限流」排隊等待入園了。
也就說,大唐芙蓉園會讓 6 萬人先進去玩,剩余的人在門口等待排隊,當有人從里面出來的時候,才允許另一個排隊的人進去。工作人員會把人數始終控制在 6 萬人以下,這樣做的目的是為了讓游玩的人有一個好的體驗,不至于造成一些意外事故,比如踩踏事件什么的,一定程度上保證了社會的穩定,也便于景區良好的口碑建立和日后的正常運營,而這種排隊限制最大人數的行為就是「限流」。
再來舉個例子,比如以車輛的限號來說,它也是限流的一種常見場景。這樣做的好處,一方面是可以保護環境盡可能少一些碳排放,另一方面能有效的緩解上、下班高峰時段的擁堵情況。尤其是在大西安,很難想象如果不限號,那么會堵成什么樣?(PS:讓原本本不富裕的生活更是雪上加霜...)
咱們再從生活中的事例回到程序當中,假設一個程序只能為 10W 人提供服務,突然有一天因為某個熱點事件,造成了系統短時間內的訪問量迅速增加到了 50W,那么導致的直接結果是系統崩潰,任何人都不能用系統了,顯然只有少人數能用遠比所有人都不能用更符合我們的預期,因此這個時候我們要使用「限流」了。
Semaphore 在創建的時候可以設置證書的數量,相當于設置了限流的最大值,再通過 release() 方法來發放證書,通過 acquire() 方法來阻塞并等待證書,這樣就通過控制證書的方式來實現限流功能了。
接下來,咱們使用代碼的方式來演示 Semaphore 的使用。我們以停車場的限流為例,假設整個停車場只有 2 個車位(車位雖少,但足矣說明問題),但來停車的卻有 5 輛車,顯然車位不夠用了,此時需要保證停車場最多只能有 2 輛車,接下來咱們使用 Semaphore 來實現車輛的限流功能,具體實現代碼如下:
import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * Author:磊哥 * By:Java中文社群 */ public class SemaphoreExample { // 創建信號量 static Semaphore semaphore = new Semaphore(2); public static void main(String[] args) { // 創建 5 個固定的線程數 ExecutorService threadPool = Executors.newFixedThreadPool(5); // 定義執行任務 Runnable runnable = new Runnable() { @Override public void run() { // 拿到當前線程的名稱 String tname = Thread.currentThread().getName(); System.out.println(String.format("老司機:%s,停車場外排隊,時間:%s", tname, new Date())); try { // 執行此行,讓所有線程先排隊等待進入停車場 Thread.sleep(100); // 執行阻塞 semaphore.acquire(); System.out.println(String.format("老司機:%s,已進入停車場,時間:%s", tname, new Date())); Thread.sleep(1000); System.out.println(String.format("老司機:%s,離開停車場,時間:%s", tname, new Date())); // 釋放鎖 semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } } }; // 執行任務 1 threadPool.submit(runnable); // 執行任務 2 threadPool.submit(runnable); // 執行任務 3 threadPool.submit(runnable); // 執行任務 4 threadPool.submit(runnable); // 執行任務 5 threadPool.submit(runnable); // 等線程池任務執行完之后關閉 threadPool.shutdown(); } }
以上代碼的執行結果如下:
從上述的結果我們可以看出,當有 5 輛車同時需要進入停車場時,因為停車場的停車位只有 2 個,所以停車場最多只能容納 2 輛車。此時我們通過 Semaphore 的 acquire 方法(阻塞等待)和 release 方法(頒發一個證書)順利的實現了限流的功能,讓停車場的車輛數始終控制在 2 輛車以下(等于或小于 2 輛車)。
我(Semaphore)實現證書控制手段有兩種,一種公平模式和非公平模式,當然為了執行的性能考慮,默認情況下我采取的是非公平的方式,具體實現可見源碼:
public Semaphore(int permits) { sync = new NonfairSync(permits); // 非公平模式 }
關于公平模式和非公平模式
所謂的公平模式就是以調用 acquire() 的先后順序來決定獲取許可證的順序的,公平模式遵循先進先出(FIFO)原則;而非公平模式是搶占式的,也就是有可能一個新的獲取線程恰好在一個許可證釋放時得到了這個許可證,而前面還有等待的線程。
顯然使用非公平的模式性能更高,因為它會把許可證發放給剛好準備好的線程,而不用再根據先后順序去“叫號”了。
當然,你可以手動選擇使用公平模式來運行 Semaphore,Semaphore 提供了兩個構造函數,源碼如下:
public Semaphore(int permits) { sync = new NonfairSync(permits); } public Semaphore(int permits, boolean fair) { sync = fair ? new FairSync(permits) : new NonfairSync(permits); }
如果想用公平模式就可以使用第二個構造函數 Semaphore(int permits, boolean fair),將 fair 值設置為 true 就是公平模式來獲取證書了。
我還提供了一些其他方法,用于實現更多的功能,詳情如下:
int availablePermits():返回此信號量中當前可用的許可證數。
int getQueueLength():返回正在等待獲取許可證的線程數。
boolean hasQueuedThreads():是否有線程正在等待獲取許可證。
boolean isFair():查詢 Semaphore 使用的是公平模式還是非公平模式,如果此信號量使用的是公平模式則返回 true。
void release(int permits):釋放給定數量的許可證,將其返回到信號量。
tryAcquire():從這個信號量獲得許可證,只有在調用時可以使用該許可證。
tryAcquire(int permits):從這個信號量獲取給定數量的許可證,只有在調用時全部可用。
tryAcquire(int permits, long timeout, TimeUnit unit):從該信號量獲取給定數量的許可證,如果在給定的等待時間內全部可用,并且當前線程尚未 interrupted。
tryAcquire(long timeout, TimeUnit unit):如果在給定的等待時間內可用,并且當前線程尚未 到達 interrupted,則從該信號量獲取許可。
void reducePermits(int reduction) :減少可用的許可證數量 reduction 個,它是 protected 方法。
Collection getQueuedThreads() :返回所有等待獲取許可證的線程集合,它是 protected 方法。
感謝各位的閱讀,以上就是“如何使用Semaphore”的內容了,經過本文的學習后,相信大家對如何使用Semaphore這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。