monitorenter原理

2018-03-30 16:08:21

認識synchronized

對於寫多線程程序的人來說,經常碰到的就是併發問題,對於容易出現併發問題的地方價格synchronized基本上就搞定 了,如果說不考慮性能問題的話,這一操絕對能應對百分之九十以上的情況,若對於性能方面有要求的話就需要額外的知識比如讀寫鎖等等。本文目的先了解透徹synchronized的基本原理。

Synchronized的基本使用

Synchronized的作用主要有三個:
(1)確保線程互斥的訪問同步代碼
(2)保證共享變量的修改能夠及時可見
(3)有效解決重排序問題。
從語法上講,Synchronized總共有三種用法:
 (1)修飾普通方法
    (2)修飾靜態方法
   (3)修飾代碼塊
  

package com.paddx.test.concurrent;

public class SynchronizedDemo {
    public void method() {
        synchronized (this) {
            System.out.println("Method 1 start");
        }
    }
}

對於上述方法我們很容易就知道是線程安全的,具體是怎麼做的到的線程安全呢,對class通過javap編譯結果如下:

 

 

monitorenter

每個對象有一個監視器鎖(monitor)。當monitor被佔用時就會處於鎖定狀態,線程執行monitorenter指令時嘗試獲取monitor的所有權,過程如下:

1、如果monitor的進入數爲0,則該線程進入monitor,然後將進入數設置爲1,該線程即爲monitor的所有者。

2、如果線程已經佔有該monitor,只是重新進入,則進入monitor的進入數加1.

3.如果其他線程已經佔用了monitor,則該線程進入阻塞狀態,直到monitor的進入數爲0,再重新嘗試獲取monitor的所有權。

monitorexit

執行monitorexit的線程必須是objectref所對應的monitor的所有者。

指令執行時,monitor的進入數減1,如果減1後進入數爲0,那線程退出monitor,不再是這個monitor的所有者。其他被這個monitor阻塞的線程可以嘗試去獲取這個 monitor 的所有權。
  通過這兩段描述,我們應該能很清楚的看出Synchronized的實現原理,Synchronized的語義底層是通過一個monitor的對象來完成,其實wait/notify等方法也依賴於monitor對象,這就是爲什麼只有在同步的塊或者方法中才能調用wait/notify等方法,否則會拋出java.lang.IllegalMonitorStateException的異常的原因。

原理總結

每個對象都有一個內部的鎖或者叫做是監視器,稱之爲monitor,當一個方法加上synchronized關鍵字的時候,如果一個線程想執行這個方法那麼首先需要獲取這個對象的monirot權限,對應到指令上面也就是需要獲取monitorenter 指令,如果一個對象獲取到這個指令之後,那麼monitor的進入數爲1,當其他線程再次獲取的時候發現這個對象的monitor對象被別的線程所佔用,那麼進入阻塞狀態,知道佔用這個對象的線程執行monitorexit,設置進入數爲0爲止。

如果synchronized加在普通方法上,那麼有效的範圍是多個線程執行同一個對象的方法。通過上面的解釋應該比較容易理解了,因爲不同的對象獲取的是不同的monitor監視器,自然也就不存在佔用–等待的過程了。如果是加載static方法上那麼需要獲取的就是這個對象所在class的Class對象,所以此時不管是幾個對象,對應的都是同一個class對象,也就是說多個線程又存在對同一個monitor的佔用—等待的過程了。所以說加載static上是對於整個類文件有效。

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