Java中Semaphore(信號量)的使用方法
Semaphore的作用:
在java中,使用了synchronized關(guān)鍵字和Lock鎖實(shí)現(xiàn)了資源的并發(fā)訪問控制,在同一時(shí)間只允許唯一了線程進(jìn)入臨界區(qū)訪問資源(讀鎖除外),這樣子控制的主要目的是為了解決多個(gè)線程并發(fā)同一資源造成的數(shù)據(jù)不一致的問題。在另外一種場景下,一個(gè)資源有多個(gè)副本可供同時(shí)使用,比如打印機(jī)房有多個(gè)打印機(jī)、廁所有多個(gè)坑可供同時(shí)使用,這種情況下,Java提供了另外的并發(fā)訪問控制--資源的多副本的并發(fā)訪問控制,今天學(xué)習(xí)的信號量Semaphore即是其中的一種。
Semaphore實(shí)現(xiàn)原理初探:
Semaphore是用來保護(hù)一個(gè)或者多個(gè)共享資源的訪問,Semaphore內(nèi)部維護(hù)了一個(gè)計(jì)數(shù)器,其值為可以訪問的共享資源的個(gè)數(shù)。一個(gè)線程要訪問共享資源,先獲得信號量,如果信號量的計(jì)數(shù)器值大于1,意味著有共享資源可以訪問,則使其計(jì)數(shù)器值減去1,再訪問共享資源。
如果計(jì)數(shù)器值為0,線程進(jìn)入休眠。當(dāng)某個(gè)線程使用完共享資源后,釋放信號量,并將信號量內(nèi)部的計(jì)數(shù)器加1,之前進(jìn)入休眠的線程將被喚醒并再次試圖獲得信號量。
就好比一個(gè)廁所管理員,站在門口,只有廁所有空位,就開門允許與空側(cè)數(shù)量等量的人進(jìn)入廁所。多個(gè)人進(jìn)入廁所后,相當(dāng)于N個(gè)人來分配使用N個(gè)空位。為避免多個(gè)人來同時(shí)競爭同一個(gè)側(cè)衛(wèi),在內(nèi)部仍然使用鎖來控制資源的同步訪問。
Semaphore的使用:
Semaphore使用時(shí)需要先構(gòu)建一個(gè)參數(shù)來指定共享資源的數(shù)量,Semaphore構(gòu)造完成后即是獲取Semaphore、共享資源使用完畢后釋放Semaphore。
Semaphore semaphore = new Semaphore(10,true); semaphore.acquire(); //do something here semaphore.release();
下面的代碼就是模擬控制商場廁所的并發(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)行共享;公平模式的信號量,先來的先獲得信號量
this.lock = new ReentrantLock(true);//公平模式的鎖,先來的先選
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();//釋放信號量,計(jì)數(shù)器加1
}
}
private int getResourceId(){
int id = -1;
lock.lock();
try {
//lock.lock();//雖然使用了鎖控制同步,但由于只是簡單的一個(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();//啟動線程
}catch (Exception e){
e.printStackTrace();
}
}
}
}
最后,Semaphore除了控制資源的多個(gè)副本的并發(fā)訪問控制,也可以使用二進(jìn)制信號量來實(shí)現(xiàn)類似synchronized關(guān)鍵字和Lock鎖的并發(fā)訪問控制功能。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java解決No enclosing instance of type PrintListFromTailToHead
這篇文章主要介紹了Java解決No enclosing instance of type PrintListFromTailToHead is accessible問題的兩種方案的相關(guān)資料,需要的朋友可以參考下2016-07-07
Java報(bào)錯(cuò)java.awt.AWTException: AWT的解決方法
在Java圖形用戶界面(GUI)編程中,java.awt.AWTException是一個(gè)常見的異常,它通常與AWT(Abstract Window Toolkit)組件相關(guān),這個(gè)異常可能在嘗試進(jìn)行與窗口、圖形環(huán)境或系統(tǒng)剪貼板等操作時(shí)拋出,本文將詳細(xì)探討AWTException的成因,并提供多種解決方案2024-12-12
Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之醫(yī)院心理咨詢問診系統(tǒng)的實(shí)現(xiàn)
這是一個(gè)使用了java+Spring+Maven+mybatis+Vue+mysql開發(fā)的醫(yī)院心理咨詢問診系統(tǒng),是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有心理咨詢問診該有的所有功能,感興趣的朋友快來看看吧2022-01-01
java實(shí)現(xiàn)單鏈表中是否有環(huán)的方法詳解
本篇文章介紹了,用java實(shí)現(xiàn)單鏈表中是否有環(huán)的方法詳解。需要的朋友參考下2013-05-05
Spring MVC學(xué)習(xí)筆記之Controller查找(基于Spring4.0.3)
這篇文章主要給大家介紹了關(guān)于Spring MVC學(xué)習(xí)筆記之Controller查找(基于Spring4.0.3)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03
Java開發(fā)實(shí)現(xiàn)飛機(jī)大戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了Java開發(fā)實(shí)現(xiàn)飛機(jī)大戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05

