關注公衆號 JavaStorm 解鎖更多併發java
在吃透 Syncchronized 原理 中介紹了關於 Synchronize
的實現原理,不管是同步方法仍是同步代碼塊,不管是ACC_SYNCHRONIZED
仍是monitorenter
、monitorexit
都是基於Monitor
實現的,那麼這篇來介紹下什麼是Monitor。編程
所謂管程:指的是管理共享變量以及對共享變量的操做過程,讓它們支持併發。翻譯爲 Java 就是管理類的成員變量和成員方法,讓這個類是線程安全的。安全
是一種程序結構,結構內的多個子程序(對象或模塊)造成的多個工做線程互斥訪問共享資源。這些共享資源通常是硬件設備或一羣變量。管程實現了在一個時間點,最多隻有一個線程在執行管程的某個子程序。與那些經過修改數據結構實現互斥訪問的併發程序設計相比,管程實現很大程度上簡化了程序設計。 管程提供了一種機制,線程能夠臨時放棄互斥訪問,等待某些條件獲得知足後,從新得到執行權恢復它的互斥訪問。數據結構
在管程的發展史上,前後出現過三種不一樣的管程模型,分別是:Hasen
模型、Hoare
模型和 MESA
模型。其中,如今普遍應用的是 MESA
模型,而且 Java
管程的實現參考的也是 MESA
模型。因此今天咱們重點介紹一下MESA
模型。併發
在併發領域,有兩個核心問題:一個是互斥,一個是同步。管程就是來解決這兩個問題的。ui
它的思路很簡單,將共享變量以及對共享變量的操做統一封裝起來。以下圖所示,管程 A 將共享變量 data 和相關的操做入隊enq()
、出隊deq()
封裝起來。線程 A 和線程 B想訪問共享變量 data ,只能經過調用管程提供的 enq()
和 deq()
。固然前提是 enq()
、deq()
保證互斥性,只容許一個線程進入管程。是否是頗有面向對象的感受。spa
在管程模型裏,共享變量和對共享變量的操做是被封裝起來的,圖中最外層的框就表明封裝的意思。框的上面只有一個入口,而且在入口旁邊還有一個入口等待隊列。當多個線程同時試圖進入管程內部時,只容許一個線程進入,其餘線程則在入口等待隊列中等待。這個過程相似就醫流程的分診,只容許一個患者就診,其餘患者都在門口等待。線程
管程裏還引入了條件變量的概念,並且每一個條件變量都對應有一個等待隊列,以下圖,條件變量 A 和條件變量 B 分別都有本身的等待隊列。翻譯
經過條件通知去喚醒等待隊列的線程競爭 鎖資源。設計
咱們經過一段代碼說明,實現一個阻塞隊列,隊列分別有出隊與入隊,都是要先獲取互斥鎖,就像管程中的入口。
notFull.await();
。notEmpty.await();
。notEmpty
對應的等待隊列。notFull
對應的等待隊列。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();
}
}
}
複製代碼
在這段示例代碼中,咱們用了 Java 併發包裏面的 Lock 和 Condition,若是你看着吃力,也不要緊,後面咱們還會詳細介紹,這個例子只是先讓你明白條件變量及其等待隊列是怎麼回事。須要注意的是:await() 和前面咱們提到的 wait() 語義是同樣的;signal() 和前面咱們提到的 notify() 語義是同樣的。管程經過條件隊列通訊實現了同步,爲咱們 Java中的併發編程提供了基本支持。
關注公衆號 JavaStorm 獲取更多併發原理