Java中Semaphore(信號(hào)量)的使用方法
Semaphore的作用:
在java中,使用了synchronized關(guān)鍵字和Lock鎖實(shí)現(xiàn)了資源的并發(fā)訪問控制,在同一時(shí)間只允許唯一了線程進(jìn)入臨界區(qū)訪問資源(讀鎖除外),這樣子控制的主要目的是為了解決多個(gè)線程并發(fā)同一資源造成的數(shù)據(jù)不一致的問題。在另外一種場(chǎng)景下,一個(gè)資源有多個(gè)副本可供同時(shí)使用,比如打印機(jī)房有多個(gè)打印機(jī)、廁所有多個(gè)坑可供同時(shí)使用,這種情況下,Java提供了另外的并發(fā)訪問控制--資源的多副本的并發(fā)訪問控制,今天學(xué)習(xí)的信號(hào)量Semaphore即是其中的一種。
Semaphore實(shí)現(xiàn)原理初探:
Semaphore是用來(lái)保護(hù)一個(gè)或者多個(gè)共享資源的訪問,Semaphore內(nèi)部維護(hù)了一個(gè)計(jì)數(shù)器,其值為可以訪問的共享資源的個(gè)數(shù)。一個(gè)線程要訪問共享資源,先獲得信號(hào)量,如果信號(hào)量的計(jì)數(shù)器值大于1,意味著有共享資源可以訪問,則使其計(jì)數(shù)器值減去1,再訪問共享資源。
如果計(jì)數(shù)器值為0,線程進(jìn)入休眠。當(dāng)某個(gè)線程使用完共享資源后,釋放信號(hào)量,并將信號(hào)量?jī)?nèi)部的計(jì)數(shù)器加1,之前進(jìn)入休眠的線程將被喚醒并再次試圖獲得信號(hào)量。
就好比一個(gè)廁所管理員,站在門口,只有廁所有空位,就開門允許與空側(cè)數(shù)量等量的人進(jìn)入廁所。多個(gè)人進(jìn)入廁所后,相當(dāng)于N個(gè)人來(lái)分配使用N個(gè)空位。為避免多個(gè)人來(lái)同時(shí)競(jìng)爭(zhēng)同一個(gè)側(cè)衛(wèi),在內(nèi)部仍然使用鎖來(lái)控制資源的同步訪問。
Semaphore的使用:
Semaphore使用時(shí)需要先構(gòu)建一個(gè)參數(shù)來(lái)指定共享資源的數(shù)量,Semaphore構(gòu)造完成后即是獲取Semaphore、共享資源使用完畢后釋放Semaphore。
Semaphore semaphore = new Semaphore(10,true); semaphore.acquire(); //do something here semaphore.release();
下面的代碼就是模擬控制商場(chǎng)廁所的并發(fā)使用:
public class ResourceManage { private final Semaphore semaphore ; private boolean resourceArray[]; private final ReentrantLock lock; public ResourceManage() { this.resourceArray = new boolean[10];//存放廁所狀態(tài) this.semaphore = new Semaphore(10,true);//控制10個(gè)共享資源的使用,使用先進(jìn)先出的公平模式進(jìn)行共享;公平模式的信號(hào)量,先來(lái)的先獲得信號(hào)量 this.lock = new ReentrantLock(true);//公平模式的鎖,先來(lái)的先選 for(int i=0 ;i<10; i++){ resourceArray[i] = true;//初始化為資源可用的情況 } } public void useResource(int userId){ semaphore.acquire(); try{ //semaphore.acquire(); int id = getResourceId();//占到一個(gè)坑 System.out.print("userId:"+userId+"正在使用資源,資源id:"+id+"\n"); Thread.sleep(100);//do something,相當(dāng)于于使用資源 resourceArray[id] = true;//退出這個(gè)坑 }catch (InterruptedException e){ e.printStackTrace(); }finally { semaphore.release();//釋放信號(hào)量,計(jì)數(shù)器加1 } } private int getResourceId(){ int id = -1; lock.lock(); try { //lock.lock();//雖然使用了鎖控制同步,但由于只是簡(jiǎn)單的一個(gè)數(shù)組遍歷,效率還是很高的,所以基本不影響性能。 for(int i=0; i<10; i++){ if(resourceArray[i]){ resourceArray[i] = false; id = i; break; } } }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } return id; } } public class ResourceUser implements Runnable{ private ResourceManage resourceManage; private int userId; public ResourceUser(ResourceManage resourceManage, int userId) { this.resourceManage = resourceManage; this.userId = userId; } public void run(){ System.out.print("userId:"+userId+"準(zhǔn)備使用資源...\n"); resourceManage.useResource(userId); System.out.print("userId:"+userId+"使用資源完畢...\n"); } public static void main(String[] args){ ResourceManage resourceManage = new ResourceManage(); Thread[] threads = new Thread[100]; for (int i = 0; i < 100; i++) { Thread thread = new Thread(new ResourceUser(resourceManage,i));//創(chuàng)建多個(gè)資源使用者 threads[i] = thread; } for(int i = 0; i < 100; i++){ Thread thread = threads[i]; try { thread.start();//啟動(dòng)線程 }catch (Exception e){ e.printStackTrace(); } } } }
最后,Semaphore除了控制資源的多個(gè)副本的并發(fā)訪問控制,也可以使用二進(jìn)制信號(hào)量來(lái)實(shí)現(xiàn)類似synchronized關(guān)鍵字和Lock鎖的并發(fā)訪問控制功能。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 詳解Java信號(hào)量Semaphore的原理及使用
- 分析Java并發(fā)編程之信號(hào)量Semaphore
- Java信號(hào)量Semaphore原理及代碼實(shí)例
- 詳解Java 信號(hào)量Semaphore
- Java 信號(hào)量Semaphore的實(shí)現(xiàn)
- Java并發(fā)編程Semaphore計(jì)數(shù)信號(hào)量詳解
- Java并發(fā)編程之Semaphore(信號(hào)量)詳解及實(shí)例
- JAVA 多線程之信號(hào)量(Semaphore)實(shí)例詳解
- Java Semaphore信號(hào)量使用分析講解
相關(guān)文章
關(guān)于Mybatis的mapper接口函數(shù)重載問題
這篇文章主要介紹了關(guān)于Mybatis的mapper接口函數(shù)重載問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02Java流程控制語(yǔ)句之If選擇結(jié)構(gòu)
今天繼續(xù)帶大家復(fù)習(xí)Java流程控制語(yǔ)句的相關(guān)知識(shí),本文對(duì)If選擇結(jié)構(gòu)作了非常詳細(xì)的介紹及代碼示例,對(duì)正在學(xué)習(xí)的小伙伴們很有幫助,需要的朋友可以參考下2021-06-06Java基礎(chǔ)之spring5新功能學(xué)習(xí)
這篇文章主要介紹了Java基礎(chǔ)之spring5新功能學(xué)習(xí),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好的幫助,需要的朋友可以參考下2021-05-05springboot動(dòng)態(tài)調(diào)用實(shí)現(xiàn)類方式
這篇文章主要介紹了springboot動(dòng)態(tài)調(diào)用實(shí)現(xiàn)類方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11AsyncHttpClient的TimeoutTimerTask連接池異步超時(shí)
這篇文章主要為大家介紹了AsyncHttpClient的TimeoutTimerTask連接池異步超時(shí)源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12java對(duì)接微信小程序詳細(xì)流程(登錄&獲取用戶信息)
這篇文章主要給大家介紹了關(guān)于java對(duì)接微信小程序(登錄&獲取用戶信息)的相關(guān)資料,我們?cè)陂_發(fā)微信小程序時(shí)經(jīng)常需要獲取用戶微信用戶名以及頭像信息,微信提供了專門的接口API用于返回這些信息,需要的朋友可以參考下2023-08-08