Java中的Semaphore信號(hào)量深入解析
Semaphore信號(hào)量
Semaphore是Java里面另外一個(gè)基本的并發(fā)工具包類,主要的的作用是用來保護(hù)共享資源的訪問的,也就是僅僅允許一定數(shù)量的線程訪問共享資源。
Semaphore維護(hù)了有限數(shù)量的許可證,只有得到了許可證的線程才能進(jìn)行共享資源的訪問,如果得不到許可證,說明當(dāng)前共享資源的訪問已經(jīng)達(dá)到最大限制,所以會(huì)掛起當(dāng)前線程,直到前面的線程處理完任務(wù)之后,把許可證歸還,后面排隊(duì)的線程才有機(jī)會(huì)獲取,然后處理任務(wù)。
這里面有兩個(gè)注意點(diǎn):
(1)大多數(shù)時(shí)候使用Semaphore都應(yīng)該是公平模式,默認(rèn)是非公平模式,如果需要公平模式可以在構(gòu)造函數(shù)里面指定,公平性可以 保證先進(jìn)先出,不會(huì)有線程饑餓問題出現(xiàn),非公平模式,不保證順序,吞吐量會(huì)更好一些。
(2)共享資源的訪問,一般指的是讀取,而不是更新,這里面不要做對(duì)共享變量的修改,除非你使用同步塊來保證。
下面我們來看下Semaphore的構(gòu)造方法:
Semaphore(int permits) //非公平模式指定最大允許訪問許可證數(shù)量 Semaphore(int permits, boolean fair)//可以通過第二個(gè)參數(shù)控制是否使用公平模
一些常用的方法:
acquire() //申請(qǐng)獲取一個(gè)許可證,如果沒有許可證,就阻塞直到能夠獲取或者被打斷 availablePermits() // 返回當(dāng)前有多少個(gè)有用的許可證數(shù)量hasQueuedThreads()//查詢是否有線程正在等待獲取許可證 drainPermits()//獲得并返回所有立即可用的許可證數(shù)量 getQueuedThreads()//返回一個(gè)List包含當(dāng)前可能正在阻塞隊(duì)列里面所有線程對(duì)象 getQueueLength()//返回當(dāng)前可能在阻塞獲取許可證線程的數(shù)量 hasQueuedThreads()//查詢是否有線程正在等待獲取許可證 isFair()//返回是否為公平模式 reducePermits(int reduction)//減少指定數(shù)量的許可證 reducePermits(int reduction)//釋放一個(gè)許可證 release(int permits)//釋放指定數(shù)量的許可證 tryAcquire()//非阻塞的獲取一個(gè)許可證
無論是Semaphore還是CountDonwLatch或者是CyclicBarrier,其實(shí)我們都可以通過Lock接口+Condition條件隊(duì)列功能來模擬實(shí)現(xiàn),但是不夠抽象所以才出現(xiàn)了AQS這個(gè)抽象的面向開發(fā)者同步框架,比如這個(gè)Semaphore,我們看下如何使用Lock實(shí)現(xiàn):
public class SemaphoreDemo2 { private final Lock lock=new ReentrantLock(true); private final Condition condition=lock.newCondition(); private int permit; public SemaphoreDemo2(int permit) { this.permit=permit; } private void acquire(){ lock.lock(); try{ if(permit==0){ condition.await();//如果超過限制,就進(jìn)入條件阻塞隊(duì)列 } System.out.println(Thread.currentThread().getName()+" 獲得資源 .... "); permit--; } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } private void release(){ lock.lock(); try{ permit++; condition.signalAll(); //每當(dāng)有一個(gè)釋放令牌,就喚醒所有等待的線程 }finally { lock.unlock(); } } }
下面我們看一下簡單的使用例子:
Semaphore semaphore=new Semaphore(3); Runnable runnable=new Runnable() { @Override public void run() { try { semaphore.acquire(); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 訪問資源......"); semaphore.release(); } }; for (int i = 0; i < 5; i++) { Thread thread=new Thread(runnable); thread.start(); } Thread.sleep(3000);
輸出結(jié)果:
Thread-0 訪問資源......
Thread-1 訪問資源......
Thread-2 訪問資源......
Thread-4 訪問資源......
Thread-3 訪問資源......
注意上面的例子只有3個(gè)許可證,我們運(yùn)行了5個(gè)線程,所以同時(shí)最多只能運(yùn)行3個(gè)線程,另外兩個(gè)會(huì)阻塞直到前面的線程歸還了許可證。
Semaphore底層原理:
Semaphore底層與CountDownLatch類似都是通過AQS的共享鎖機(jī)制來實(shí)現(xiàn)的,指定的數(shù)量會(huì)設(shè)置到AQS里面的state里面,然后對(duì)于每一個(gè) 調(diào)用acquire方法線程,state都會(huì)減去一,如果state等于0,那么調(diào)用該方法的線程會(huì)被添加到同步隊(duì)列里面,同時(shí)使用 LockSupport.park方法掛起等待,知道有線程調(diào)用了release方法,會(huì)對(duì)state加1,然后喚醒共享隊(duì)列里面的線程,注意這里如果是 公平模式,就直接喚醒下一個(gè)等待線程即可,如果是非公平模式就允許新加入的線程與已有的線程進(jìn)行競(jìng)爭(zhēng),誰先得到就是誰的,如果新加入的 競(jìng)爭(zhēng)失敗,就會(huì)走公平模式進(jìn)入隊(duì)列排隊(duì)。
總結(jié):
本文主要介紹了并發(fā)工具包Semaphore其主要作用來限制對(duì)于共享資源的訪問,接著我們又介紹了其特點(diǎn),使用及注意事項(xiàng),然后又給出了使用其他同步工具Lock+Condition實(shí)現(xiàn)的Semaphore
到此這篇關(guān)于Java中的Semaphore信號(hào)量深入解析的文章就介紹到這了,更多相關(guān)Semaphore信號(hào)量深入解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java.lang.NullPointerException的錯(cuò)誤解決
Java中NullPointerException是一種常見的運(yùn)行時(shí)異常,通常發(fā)生在嘗試調(diào)用null對(duì)象的方法或訪問其屬性時(shí),具有一定的參考價(jià)值,感興趣的可以了解一下2024-09-09springboot websocket集群(stomp協(xié)議)連接時(shí)候傳遞參數(shù)
這篇文章主要介紹了springboot websocket集群(stomp協(xié)議)連接時(shí)候傳遞參數(shù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07servlet監(jiān)聽實(shí)現(xiàn)統(tǒng)計(jì)在線人數(shù)功能 附源碼下載
這篇文章主要為大家詳細(xì)介紹了servlet監(jiān)聽統(tǒng)計(jì)在線人數(shù)的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04Java使用代理進(jìn)行網(wǎng)絡(luò)連接方法示例
這篇文章主要介紹了Java使用代理進(jìn)行網(wǎng)絡(luò)連接方法示例,內(nèi)容十分詳細(xì),需要的朋友可以參考下。2017-09-09