Java中Semaphore(信號量)的使用

Semaphore的做用:java

在java中,使用了synchronized關鍵字和Lock鎖實現了資源的併發訪問控制,在同一時間只容許惟一了線程進入臨界區訪問資源(讀鎖除外),這樣子控制的主要目的是爲了解決多個線程併發同一資源形成的數據不一致的問題。在另一種場景下,一個資源有多個副本可供同時使用,好比打印機房有多個打印機、廁全部多個坑可供同時使用,這種狀況下,Java提供了另外的併發訪問控制--資源的多副本的併發訪問控制,今天學習的信號量Semaphore便是其中的一種。數組

Semaphore實現原理初探:併發

Semaphore是用來保護一個或者多個共享資源的訪問,Semaphore內部維護了一個計數器,其值爲能夠訪問的共享資源的個數。一個線程要訪問共享資源,先得到信號量,若是信號量的計數器值大於1,意味着有共享資源能夠訪問,則使其計數器值減去1,再訪問共享資源。性能

若是計數器值爲0,線程進入休眠。當某個線程使用完共享資源後,釋放信號量,並將信號量內部的計數器加1,以前進入休眠的線程將被喚醒並再次試圖得到信號量。學習

就比如一個廁所管理員,站在門口,只有廁全部空位,就開門容許與空側數量等量的人進入廁所。多我的進入廁所後,至關於N我的來分配使用N個空位。爲避免多我的來同時競爭同一個側衛,在內部仍然使用鎖來控制資源的同步訪問。ui

Semaphore的使用:this

Semaphore使用時須要先構建一個參數來指定共享資源的數量,Semaphore構造完成後便是獲取Semaphore、共享資源使用完畢後釋放Semaphore。spa

Semaphore semaphore = new Semaphore(10,true);
semaphore.acquire();
//do something here
semaphore.release();

下面的代碼就是模擬控制商場廁所的併發使用:線程

public class ResourceManage {
    private final Semaphore semaphore ;
    private boolean resourceArray[];
    private final ReentrantLock lock;
    public ResourceManage() {
        this.resourceArray = new boolean[10];//存放廁所狀態
        this.semaphore = new Semaphore(10,true);//控制10個共享資源的使用,使用先進先出的公平模式進行共享;公平模式的信號量,先來的先得到信號量
        this.lock = new ReentrantLock(true);//公平模式的鎖,先來的先選
        for(int i=0 ;i<10; i++){
            resourceArray[i] = true;//初始化爲資源可用的狀況
        }
    }
    public void useResource(int userId){
        try{
            semaphore.acquire();
            int id = getResourceId();//佔到一個坑
            System.out.print("userId:"+userId+"正在使用資源,資源id:"+id+"\n");
            Thread.sleep(100);//do something,至關於於使用資源
            resourceArray[id] = true;//退出這個坑
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            semaphore.release();//釋放信號量,計數器加1
        }
    }
    private int getResourceId(){
        int id = -1;
        try {
            lock.lock();//雖然使用了鎖控制同步,但因爲只是簡單的一個數組遍歷,效率仍是很高的,因此基本不影響性能。
            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+"準備使用資源...\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));//建立多個資源使用者
            threads[i] = thread;
        }
        for(int i = 0; i < 100; i++){
            Thread thread = threads[i];
            try {
                thread.start();//啓動線程
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

最後,Semaphore除了控制資源的多個副本的併發訪問控制,也可使用二進制信號量來實現相似synchronized關鍵字和Lock鎖的併發訪問控制功能。
code

相關文章
相關標籤/搜索