Java中的管程模型

 

操作系統使用信號量解決併發問題,Java選擇使用管程(Monitor)解決併發問題。信號量和管程是等價的,可以使用信號量實現管程,也可以使用管程實現信號量。

管程就是指管理共享變量,以及對共享變量的相關操作。具體到 Java 語言中,管程就是管理類的成員變量和方法,讓這個類是線程安全的。管程的發展史中,先後出現過三種管程模型,Hasen 模型、Hoare 模型和 MESA 模型,Java 使用的是 MESA 模型。

我們用管程模型主要是解決併發編程中的兩個核心問題,互斥同步。互斥是指同一時刻只允許一個線程訪問共享資源,同步則是指線程之間如何通信、寫作。

那麼,Java 所採用的 MESA 模型是如何解決互斥和同步問題的呢?

MESA 解決互斥問題

管程模型解決互斥問題的方法是:將共享變量及對共享變量的操作統一封裝起來。

如下圖所示,管程 X 將共享變量 queue,及其入隊出隊操作 enq() 和 dep() 封裝起來。線程 A 和線程 B 想要訪問共享變量 queue,就需要通過 enq() 和 deq() 來實現,而 enq() 和 deq() 保證互斥,只允許一個線程進入管程。

 

MESA 解決同步問題

MESA 模型解決同步問題可以類比去醫院就醫。患者首先需要排隊等待醫生叫好,醫生診斷被叫到號的患者。期間,患者如果需要進行其他輔助的檢查,比如說排個 X 光,就需要去等待拍 X 光的醫生叫好。患者拍完 X 光之後,再次回到上一個醫生那裏,等待醫生再次診斷。

醫院排隊

管程模型與看醫生的流程類似,管程入口處有一個等待隊列。當多個線程試圖進入管程內部的時候,只允許一個線程進入,其他線程在等待隊列中等待。就和看醫生的時候排隊一樣。

管程中還有一個條件變量的概念,每個條件變量對應一個條件變量等待隊列。比如說有一個條件變量 A,當執行線程 T1 時發現不滿足條件變量 A,T1 就會進入條件變量 A 的等待隊列中。就像去看醫生,醫生讓你先去排個 X 光,就要去拍 X 光的地方排隊。

當執行線程 T2 時發現滿足條件變量 A,就會喚醒條件變量 A 等待中的線程 T1,線程 T1 就會再次進入到入口等待隊列。就像拍完 X 光的人,再去看醫生。

MESA 管程模型

public class BlockedQueue<T>{
  final Lock lock =
    new ReentrantLock();
  // 條件變量:隊列不滿  
  final Condition notFull =
    lock.newCondition();
  // 條件變量:隊列不空  
  final Condition notEmpty =
    lock.newCondition();

  // 入隊
  void enq(T x) {
    lock.lock();
    try {
      while (隊列已滿){
        // 等待隊列不滿 
        notFull.await();
      }  
      // 省略入隊操作...
      //入隊後,通知可出隊
      notEmpty.signal();
    }finally {
      lock.unlock();
    }
  }
  // 出隊
  void deq(){
    lock.lock();
    try {
      while (隊列已空){
        // 等待隊列不空
        notEmpty.await();
      }
      // 省略出隊操作...
      //出隊後,通知可入隊
      notFull.signal();
    }finally {
      lock.unlock();
    }  
  }
}
  1. 對於入隊操作,如果隊列已滿,就需要等待直到隊列不滿,所以這裏用了notFull.await();。
  2. 對於出隊操作,如果隊列爲空,就需要等待直到隊列不空,所以就用了notEmpty.await();。
  3. 如果入隊成功,那麼隊列就不空了,就需要通知條件變量:隊列不空notEmpty對應的等待隊列。
  4. 如果出隊成功,那就隊列就不滿了,就需要通知條件變量:隊列不滿notFull對應的等待隊列。

synchronized 單條件變量的管程模型

Java 參考了 MESA 模型,語言內置的管程(synchronized)對 MESA 模型進行了精簡。MESA 模型中,條件變量可以有多個,Java 語言內置的管程裏只有一個條件變量。

Java SDK 併發包實現的管程支持多個條件變量,不過併發包裏的鎖,需要開發人員自己進行加鎖和解鎖操作。

相關文章

08 | 管程:併發編程的萬能鑰匙

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章