java并發編程之Semaphore

Semaphore,信號量,一般用來控制同時訪問特定共享資源的線程數,它通過協調各個線程來保證使用公共資源的合理性。

應用場景

Semaphore,從字面上其實不太好理解它的意思,換個通俗易懂的比喻吧,Semaphore就好比是馬路上控制流量的紅綠燈。比如上地五街,需要限流,只允許同時有100輛車通過,其他的車輛都必須在路口等待,所以對于前100輛車,它們將會看到綠燈,可以開進這條馬路,后面的車會看到紅燈,不能駛入,但是如果前100輛車中有20輛車已經駛離上地五街,那么后面的等待車輛允許20輛車駛入。這個例子中車就是線程,駛入馬路的車表示正在執行的線程,離開馬路的車表示已經執行完成的線程,看見紅燈表示線程被阻塞,看見綠燈表示線程可以執行。

這樣就很好理解了,Semaphore它主要被用來控制流量,特別是公共資源有限的業務場景。

案例
  • 需求:公共緩存,同一時刻只允許3個線程訪問。

  • 分析及代碼實現
    公共緩存就類比為馬路,訪問的線程類比為駛入車輛,需要控制同一時刻只能有3輛車駛入該馬路。

注:本文只給出一個簡單的demo,表明Semaphore的具體使用方式。

Semaphore使用.png
  • Semaphore聲明:
    Semaphore的構造函數接受int型參數,表示可用的許可證數量,如果在同一時刻允許N個線程獲取許可證,就傳入N;

  • 線程調用Semaphore的acquire方法獲取許可證,獲取許可證的實質也就是獲取同步器的同步狀態;

  • 使用完成之后調用release方法釋放許可證,釋放許可證的實質也就是釋放同同步狀態。

Semaphore源碼分析

Semaphore同Lock一樣,也是自定義AQS同步組件,接下來就以自定義同步器、acquire方法和release方法為切入點詳細分析Semaphore的具體實現。

  • 自定義同步器


    Sync實現

    從Sync的代碼可以看出:

    • Semaphore的同步器獲取同步狀態的方式是共享式的;
    1. Semaphore提供兩種自定義同步器:公平與非公平同步器。換句話說,Semaphore的限流對線程的協調可以是公平的,也可以是非公平的。

    非公平同步器NonfairSync

    NonfairSync實現

    公平同步器FairSync

    FairSync實現

    對于公平和非公平其實僅限于對同步狀態的獲取方式上,是搶占式還是非搶占式的,對比源碼可以看出,公平式同步器在獲取同步狀態之前會判斷獲取同步狀態的當前線程的前面是否已有其他線程正在等待獲取同步狀態,如果有,當前線程進入同步隊列等待,而非公平式同步器在獲取同步狀態時不做該操作,當前線程是否能獲取到同步狀態由具體的線程調度決定。

  • 構造方法


    構造方法

    Semaphore提供兩個構造方法以供使用者使用,從構造方法實現可以看出:

    • 構造方法傳入的int型參數permits其實就是同步器的同步狀態;

    • 到底是非公平還是公平由boolean型參數fair決定,不帶fair參數默認創建非公平式同步器。

  • acquire實現


    acquire實現

    Semaphore的acquire操作實質是獲取同步狀態。本文只給出常用的不帶參數的acquire()方法的具體實現,至于acquire操作的其他實現,有興趣的同學可以自行閱讀源碼,它們的本質沒有什么區別。

  • release實現
    Semaphore提供帶參數的release和不帶參數的release:


    release實現

    release操作的實質是釋放同步狀態,調用不帶參數的release后,同步器的同步狀態state = state - 1,而調用帶參數的release后,state = state - 傳入參數permits。

  • 其他方法
    Semaphore還提供一些其他的方法,方便使用者使用:

    • public int availablePermits()
      返回此信號量中當前可用的許可證數量;

    • protected void reducePermits(int reduction)
      減少許可證數量,減少的數量 = 傳入參數reduction;

    • public final boolean hasQueuedThreads()
      是否有線程正在等待獲取許可證;

    • public final int getQueueLength()
      返回正在等待獲取許可證的線程數量;

    • protected Collection<Thread> getQueuedThreads()
      返回所有等待獲取許可證的線程集合。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容