首頁 >Java >java教程 >Monitor(管程)是什麼意思? Java中Monitor(管程)的介紹

Monitor(管程)是什麼意思? Java中Monitor(管程)的介紹

不言
不言原創
2018-09-17 15:12:1867475瀏覽


Monitor(管程)是什麼意思? Java中Monitor(管程)的介紹

本篇文章帶給大家的內容是關於Monitor(管程)是什麼意思? Java中Monitor(管程)的介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

monitor的概念

管程,英文是Monitor,也常被翻譯為“監視器”,monitor 不管是翻譯為“管程”還是“監視器”,都是比較晦澀的,透過翻譯後的中文,並無法對monitor 達到一個直觀的描述。
在《作業系統同步原語》 這篇文章中,介紹了作業系統在面對 進程/執行緒間同步的時候,所支援的一些同步原語,其中semaphore 訊號量和mutex 互斥量是最重要的同步原語。
在使用基本的 mutex 進行並發控制時,需要程式設計師非常小心地控制 mutex 的 down 和 up 操作,否則很容易引起死鎖等問題。為了更容易地寫出正確的並發程序,所以在mutex 和semaphore 的基礎上,提出了更高層次的同步原語monitor,不過需要注意的是,作業系統本身並不支援monitor 機制,實際上,monitor是屬於程式語言的範疇,當你想要使用monitor 時,先了解語言本身是否支援monitor 原語,例如C 語言它就不支援monitor,Java 語言支援monitor。
一般的 monitor 實作模式是程式語言在語法上提供語法糖,而如何實作 monitor 機制,則屬於編譯器的工作,Java 就是這麼幹的。

monitor 的重要特點是,同一個時刻,只有一個 進程/執行緒 能進入 monitor 中定義的臨界區,這使得 monitor 能夠達到互斥的效果。但僅僅有互斥的作用是不夠的,無法進入 monitor 臨界區的 進程/線程,它們應該被阻塞,並且在必要的時候會被喚醒。顯然,monitor 作為一個同步工具,也應該提供這樣的管理 進程/執行緒 狀態的機制。想想我們為什麼覺得 semaphore 和 mutex 在程式設計上容易出錯,因為我們需要去親自操作變數以及對 進程/執行緒 進行阻塞和喚醒。 monitor 這個機制之所以被稱為“更高級的原語”,那麼它就不可避免地需要對外屏蔽掉這些機制,並且在內部實現這些機制,使得使用monitor 的人看到的是一個簡潔易用的接口。

monitor 基本元素

monitor 機制需要幾個元素來配合,分別是:

  1. 臨界區

  2. monitor 物件及鎖定

  3. 條件變數以及定義在monitor 物件上的wait,signal 操作。

使用monitor 機制的目的主要是為了互斥進入臨界區,為了做到能夠阻塞無法進入臨界區的進程/線程,還需要一個monitor object 來協助,這個monitor object 內部會有對應的資料結構,例如列表,來保存被阻塞的線程;同時由於monitor 機製本質上是基於mutex 這種基本原語的,所以monitor object 還必須維護一個基於mutex 的鎖。
此外,為了在適當的時候能夠阻塞和喚醒進程/線程,還需要引入一個條件變量,這個條件變量用來決定什麼時候是“適當的時候”,這個條件可以來自程式碼的邏輯,也可以是在monitor object 的內部,總而言之,程式設計師對條件變數的定義有很大的自主性。不過,由於 monitor object 內部採用了資料結構來保存被阻塞的佇列,因此它也必須對外提供兩個 API 來讓執行緒進入阻塞狀態以及之後被喚醒,分別是 wait 和 notify。

Java 語言對 monitor 的支援

monitor 是作業系統提出來的一種高階原語,但其具體的實作模式,不同的程式語言都有可能不一樣。以下以 Java 的 monitor 為例子,來說明 monitor 在 Java 中的實作方式。

臨界區的圈定

在Java 中,可以採用synchronized 關鍵字來修飾實例方法、類別方法以及程式碼區塊,如下所示:

/**
 * @author beanlam
 * @version 1.0
 * @date 2018/9/12
 */
public class Monitor {

    private Object ANOTHER_LOCK = new Object();

    private synchronized void fun1() {
    }

    public static synchronized void fun2() {
    }

    public void fun3() {
        synchronized (this) {
        }
    }

    public void fun4() {
        synchronized (ANOTHER_LOCK) {
        }
    }
}

被synchronized 關鍵字修飾的方法、程式碼區塊,就是monitor 機制的臨界區。

monitor object

可以發現,上述的synchronized 關鍵字在使用的時候,往往需要指定一個物件與之關聯,例如synchronized(this),或者synchronized(ANOTHER_LOCK),synchronized 如果修飾的是實例方法,那麼其關聯的物件其實就是this,如果修飾的是類別方法,那麼其關聯的物件就是this.class。總之,synchronzied 需要關聯一個對象,而這個物件就是 monitor object。
monitor 的機制中,monitor object 扮演著維護 mutex以及定義 wait/signal API 來管理執行緒的阻塞和喚醒的角色。
Java 語言中的 java.lang.Object 類,便是滿足這個要求的對象,任何一個 Java 物件都可以作為 monitor 機制的 monitor object。
Java 物件儲存在記憶體中,分別分為三個部分,即物件頭、實例資料和對齊填充,而在其物件頭中,保存了鎖定標識;同時,java.lang.Object 類別定義了wait (),notify(),notifyAll() 方法,這些方法的具體實現,依賴於一個叫做ObjectMonitor 模式的實現,這是JVM 內部基於C 實現的一套機制,基本原理如下所示:

Monitor(管程)是什麼意思? Java中Monitor(管程)的介紹

當一個執行緒需要取得Object 的鎖定時,會放入EntrySet 中進行等待,如果該執行緒取得了鎖定,成為目前鎖定的owner。如果根據程式邏輯,一個已經獲得了鎖的執行緒缺少某些外部條件,而無法繼續進行下去(例如生產者發現佇列已滿或消費者發現佇列為空),那麼該執行緒可以透過呼叫wait 方法將鎖釋放,進入wait set 中阻塞進行等待,其它線程在這個時候有機會獲得鎖,去乾其它的事情,從而使得之前不成立的外部條件成立,這樣先前被阻塞的線程就可以重新進入EntrySet 去競爭鎖。這個外部條件在 monitor 機制中稱為條件變數。

synchronized 關鍵字

synchronized 關鍵字是 Java 在文法層面上,用來讓開發者方便地進行多執行緒同步的重要工具。要進入一個 synchronized 方法修飾的方法或程式碼區塊,會先取得與 synchronized 關鍵字綁定在一起的 Object 的物件鎖,這個鎖也限定了其它執行緒無法進入與這個鎖相關的其它 synchronized 程式碼區域。

網路上很多文章以及資料,在分析 synchronized 的原理時,基本上都會說 synchronized 是基於 monitor 機制實現的,但很少有文章說清楚,都是模糊帶過。
參考前面提到的 Monitor 的幾個基本元素,如果 synchronized 是基於 monitor 機制實現的,那麼對應的元素分別是什麼?
它必須要有臨界區,這裡的臨界區我們可以認為是物件頭 mutex 的 P 或 V 操作,這是個臨界區
那 monitor object 對應哪一個呢? mutex?總之無法找到真正的 monitor object。
所以我認為「synchronized 是基於 monitor 機制實現的」這樣的說法是不正確的,是模棱兩可的。
Java 提供的 monitor 機制,其實是 Object,synchronized 等元素合作形成的,甚至說外部的條件變數也是個組成部分。 JVM 底層的 ObjectMonitor 只是用來輔助實作 monitor 機制的常用模式,但大多數文章都把 ObjectMonitor 直接當成了 monitor 機制。
我覺得應該這麼理解:Java 對monitor 的支持,是以機制的粒度提供給開發者使用的,也就是說,開發者要結合使用synchronized 關鍵字,以及Object 的wait / notify 等元素​​,才能說自己利用monitor 的機制去解決了一個生產者消費者的問題。



以上是Monitor(管程)是什麼意思? Java中Monitor(管程)的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn