信號(hào)量(Semaphore),接受多個(gè)線程同時(shí)訪問(wèn)

1、引入信號(hào)量(Semaphore)

信號(hào)量為多線程提供更為強(qiáng)大的控制方法。廣義上說(shuō),信號(hào)量是對(duì)鎖的擴(kuò)展。無(wú)論是內(nèi)部鎖synchronized還是重入鎖ReentrantLock,一次都只允許一個(gè)線程訪問(wèn)一個(gè)資源,而信號(hào)量可以指定多個(gè)線程,同時(shí)訪問(wèn)某一個(gè)資源。
信號(hào)量主要提供了以下構(gòu)造函數(shù):

public Semaphore(int permits)
public Semaphore(int permits, boolean fair)

在構(gòu)造信號(hào)量對(duì)象時(shí),,必須指定信號(hào)量的準(zhǔn)入數(shù),即同時(shí)能申請(qǐng)多少個(gè)許可。當(dāng)每個(gè)線程每次只申請(qǐng)一個(gè)許可時(shí),這就相當(dāng)于制定了同時(shí)有多少個(gè)線程可以訪問(wèn)某一資源。

2、信號(hào)量的主要邏輯方法

public void acquire()
public void acquireUninterruptibly()
public boolean tryAcquire()
public boolean tryAcquire(long timeout, TimeUnit unit)
public void release()
  • acquire()方法嘗試獲得一個(gè)準(zhǔn)入的許可。若無(wú)法獲得,則線程會(huì)等待,直到有線程釋放一個(gè)許可或當(dāng)前線程被中斷。
  • acquireUninterruptibly()方法和acquire()類似,但不響應(yīng)中斷。
  • tryAcquire()嘗試獲得一個(gè)許可,如果成功返回true,失敗則返回false,它不會(huì)進(jìn)行等待,立即返回。
  • tryAcquire(long timeout, TimeUnit unit)嘗試在指定的時(shí)間內(nèi)獲得一個(gè)許可。
  • release()方法用于在線程訪問(wèn)資源結(jié)束后,釋放一個(gè)許可。以使其他等待許可的線程可以進(jìn)行資源訪問(wèn)。

3、簡(jiǎn)單演示一下Semaphore功能

演示代碼如下:

public class SemaphoreDemo implements Runnable
{
    //聲明了一個(gè)包含五個(gè)許可的信號(hào)量。這就意味著同時(shí)可以有5個(gè)線程進(jìn)入臨界區(qū)
    final Semaphore semaphore = new Semaphore(5);

    @Override
    public void run()
    {
        try
        {
            semaphore.acquire();
            //模擬耗時(shí)操作
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getId() + ":done!");
            semaphore.release();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    public static void  main(String[] args)
    {
        ExecutorService exec = Executors.newFixedThreadPool(20);
        final SemaphoreDemo demo = new SemaphoreDemo();
        for (int i = 0; i < 20; ++i)
        {
            exec.submit(demo);
        }
    }

}

上述代碼中,下面代碼塊為臨界區(qū)管理代碼,程序會(huì)限制執(zhí)行這段代碼的線程數(shù)。申明了一個(gè)包含5個(gè)許可的信號(hào)量,這就意味著同時(shí)可以有5個(gè)線程進(jìn)入下面臨界區(qū)代碼段。申請(qǐng)信號(hào)量使用acquire()操作,在離開(kāi)時(shí),務(wù)必使用release()釋放信號(hào)量,這就和釋放鎖一個(gè)道理。如果不幸發(fā)生了信號(hào)量泄露(申請(qǐng)了但沒(méi)釋放),那么可以進(jìn)入臨界區(qū)的線程數(shù)就會(huì)越來(lái)越少,直到所有的線程均不可訪問(wèn)。在本例中,同時(shí)開(kāi)啟了20個(gè)線程。觀察這段程序的輸出,會(huì)發(fā)現(xiàn)系統(tǒng)以5個(gè)線程為一組,依次輸出帶有線程ID的文本。

 //模擬耗時(shí)操作
 Thread.sleep(2000);
 System.out.println(Thread.currentThread().getId() + ":done!");
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容