1. 程式人生 > >Semaphore訊號量類詳解

Semaphore訊號量類詳解

Semaphore類是一個計數訊號量,必須由獲取它的執行緒釋放,通常用於限制可以訪問某些資源(物理或邏輯的)執行緒數目,訊號量控制的是執行緒併發的數量。

計數器:一個訊號量有且僅有3種操作,且它們全部是原子的:初始化、增加和減少
增加可以為一個程序解除阻塞;
減少可以讓一個程序進入阻塞。

原理理解:
Semaphore是用來保護一個或者多個共享資源的訪問,Semaphore內部維護了一個計數器,其值為可以訪問的共享資源的個數。一個執行緒要訪問共享資源,先獲得訊號量,如果訊號量的計數器值大於1,意味著有共享資源可以訪問,則使其計數器值減去1,再訪問共享資源。
如果計數器值為0,執行緒進入休眠。當某個執行緒使用完共享資源後,釋放訊號量,並將訊號量內部的計數器加1,之前進入休眠的執行緒將被喚醒並再次試圖獲得訊號量。

構造方法:
Semaphore有兩個構造方法 Semaphore(int)、Semaphore(int,boolean)
引數中的int表示該訊號量擁有的許可數量,boolean表示獲取許可的時候是否是公平的

方法區:
初始化:
Semaphore(int permits)引數permits就是允許同時執行的執行緒數目;
獲取訊號:
semaphore.acquire();獲取一次執行的機會,可以指定每次動態獲取的次數  例如:每次獲取3個semaphore.acquire(3);
釋放訊號:
release()、release(int)
檢視現在可用的訊號量,返回int
semaphore.availablePermits()
獲得喚醒呼叫,從訊號量中獲取兩個許可,並且在獲得許可之前,一直將執行緒阻塞。
semaphore.acquireUninterruptibly(2);
返回當前許可數,全部排掉清0
semaphore.drainPermits()

思考:
在很多情況下,可能有多個執行緒需要訪問數目很少的資源。假想在伺服器上執行著若干個回答客戶端請求的執行緒。這些執行緒需要連線到同一資料庫,但任一時刻只能獲得一定數目的資料庫連線。你要怎樣才能夠有效地將這些固定數目的資料庫連線分配給大量的執行緒?
   
答:1.給方法加同步鎖,保證同一時刻只能有一個人去呼叫此方法,其他所有執行緒排隊等待,但是此種情況下即使你的資料庫連結有10個,也始終只有一個處於使用狀態。這樣將會大大的浪費系統資源,而且系統的執行效率非常的低下。
    2.另外一種方法當然是使用訊號量,通過訊號量許可與資料庫可用連線數相同的數目,將大大的提高效率和效能。
    
例:停車位
package com.lt.thread.SamephoreTest;
import java.util.concurrent.Semaphore;

public class Parking implements Runnable {
    private int count;
    private Semaphore semaphore;
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
    public Semaphore getSemaphore() {
        return semaphore;
    }
    public void setSemaphore(Semaphore semaphore) {
        this.semaphore = semaphore;
    }
    public Parking(int count)
    {
        this.count=count;
        this.semaphore=new Semaphore(count);
    }
    public void parking()
    {
        try {
            semaphore.acquire();
            try {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName()+" find a paking space");
            }
           catch (InterruptedException e)
           {
               e.printStackTrace();
           }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        finally {
            System.out.println(Thread.currentThread().getName()+" release a paking space");
            semaphore.release();
        }
    }
    @Override
    public void run()
    {
        this.parking();
    }
    public static void main(String[] args)
    {
        Parking parking=new Parking(5);
        Thread[] threads=new Thread[13];
        for (int i=0;i<threads.length;i++)
        {
            threads[i]=new Thread(parking,"thread"+i);
        }
        for (int i=0;i<threads.length;i++)
        {
            threads[i].start();
        }
    }

}   

更多實時精彩分享請關注微信公眾號