多線程——Synchronized原理實現

前言:為什么使用synchronized?

在多線程編程中,一個資源會被多個線程共享,為了避免因為資源搶占導致數據錯亂,所以要對線程進行同步。因此,引入synchronized關鍵字。

以下,來探究下synchronized的使用和底層原理。

一、synchronized的作用

1.1原子性

原子性:指一個操作或多個操作,要么全部執行,要么全部不執行。

java中,賦值和讀取值的操作都是原子的。

但是i++,i+=1等操作不是原子的,因為這些操作在底層是不是一個操作,而是被分成了讀取,計算,賦值幾步操作,所以保證這幾步的原子性,才能保證i++的原子性。

注意:synchronized 可以保證原子性,但是volatile不能保證原子性。

1.2 可見性

可見性:指多線程訪問同一資源時,該資源對所有線程都是可見的。

synchronized對一個資源加鎖之后,在釋放鎖之前會將變量的修改刷新到主內存中,保證資源的可見的。

1.3 有序性

有序性:指程序中的代碼會按照一定的順序執行。

在java中,有編譯器重排,指令級重排以及系統重排,這些指令重排會使指令實際執行的順序與實際可見的順序不同。

synchronized保證了指令不會被重排,按照顯示的順序執行。

:synchronized是可重入的。即一個線程已經獲取該資源的synchronized鎖時,還可以再次獲得該資源的鎖。

二、synchronized的作用范圍

synchronized關鍵字可以修飾靜態方法,實例函數,代碼塊。

public class SyncDemo {
    // 修飾靜態方法,對類加鎖
    public static synchronized void test1(){
    }

    // 修飾實例方法,對實例對象加鎖
    public synchronized void test2(){
        //修飾代碼塊,對類加鎖
        synchronized (SyncDemo.class){
        }
    }
    public void test3(){
        // 修飾代碼塊,對當前對象,即實例方法加鎖
        synchronized (this){
        }
    }

    public static void main(String[] args) {

    }
}

2.1 修飾靜態方法

由類加載機制可以知道,靜態方法是和類同時加載的,歸屬于類。所以當synchronized修飾靜態方法時,是對類加鎖。

2.2 修飾實例方法

synchronized修飾實例方法 ,即對當前實例方法加鎖。

2.3 修飾代碼塊

如上代碼:修飾的第一個代碼塊是對實例方法加鎖,修飾的第二個代碼塊是對類加鎖。所以修飾代碼塊時,是可以選擇加鎖對象的。

三、synchronized底層原理

我們將上述代碼反編譯成字節碼,看看底層實現原理。

從class字節碼文件可以看出,一個通過方法flags標志,一個是通過monitorenter和monitorexit指令

3.1 修飾實例方法


可以看出,synchronized修飾實例方法時,是在方法的flags里面加了一個ACC_SYNCHRONIZED標志。

此標志表示JVM這是一個同步方法,該線程進入該方法時,需要先獲取對應的鎖,且鎖計數器加1,釋放時減1.

3.2 修飾代碼塊

從反編譯的字節碼可以看出,同步代碼塊是由monitorexit指令進入,然后monitorexit釋放鎖。

但是截圖中可以看出,有兩個monitorexit,這里為什么有兩個monitorexit?

第二個monitorexit是來處理異常的。正常情況下,第一個monitorexit之后會執行goto指令,而該指令的返回是后面的return。正常情況下只會執行第一個monitorexit釋放鎖,然后返回。

而如果執行中發生了異常,第二個monitorexit起作用了,它由編譯器自動生成,發生異常時處理異常,然后釋放鎖的。


四、synchronized鎖的底層原理實現

上面我們了解了JVM中如何實現synchronized鎖的,但是JVM中如何對對象加鎖的呢?

JVM中,對象由三部分構成:對象頭,實例數據,對齊填充。


先簡單介紹下實例數據和對齊填充:
實例數據:存放類的屬性數據信息,包括父類的屬性信息。如果是數組實例,還包括數組的長度。
對齊填充:不是必需部分,是虛擬機要求對象地址是8字節的整數倍,所以僅僅是用來字節對齊。
對象頭:包括兩個部分,Mark Word和Class Metadata Address。Mark Word存儲對象的hashCode,鎖信息,和分代年齡等信息;而后者記錄指針指向對象的類元信息,即確定對象是哪個類的實例。

鎖的狀態
額外說明下鎖的狀態,在JDK1.6之前,鎖只有無鎖和重量級鎖兩個狀態。在JDK1.6之后,對synchronized鎖進行了優化,鎖狀態有四個:無鎖狀態,偏向鎖,輕量級鎖,重量級鎖。

五、synchronized鎖的優化

因為JDK1.6之前,只有重量級鎖,所以使用synchronized會造成很大的消耗,所以之后,對synchronized鎖進行了優化。

5.1 偏向鎖

針對使用了synchronized鎖,但是實際操作時,不存在鎖競爭時,會加上偏向鎖。頭對象會標記偏向鎖的狀態位,見上圖。

這樣就減少了同一線程獲取鎖的代價。

5.2 輕量級鎖

由偏向鎖升級而來,當存在第二個鎖申請同一個鎖對象時,偏向鎖就會升級為輕量級鎖。

5.3 重量級鎖

由輕量級鎖升級而來,當同一時間有多個線程競爭鎖時,鎖會倍升級為重量級鎖。

5.4 鎖升級

鎖的狀態會一步步升級,無鎖——>偏向鎖——> 輕量級鎖——> 重量級鎖。而且鎖的升級是不可逆的。即升級到輕量級鎖,重量級鎖,是無法自動恢復到無鎖,偏向鎖的狀態的。

5.5 鎖消除

鎖消除是JVM另一種鎖優化機制,指編譯時,對上下文的分析,去除不可能存在競爭的鎖。

5.6 鎖粗化

鎖粗化也是JVM的一種鎖優化機制,通過擴大鎖的范圍,避免反復的加鎖和釋放鎖。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370