Java中的管程模型

Java中的管程模型

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

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

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

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

MESA 解決互斥問題

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

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

管程模型的代碼化語義

MESA 解決同步問題

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

醫院排隊

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

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

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

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 併發包實現的管程支持多個條件變量,不過併發包裏的鎖,須要開發人員本身進行加鎖和解鎖操做。

Java 中的管程示意圖

相關文章

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

相關文章
相關標籤/搜索