1. 程式人生 > >巨人大哥談Java中的Synchronized關鍵字用法

巨人大哥談Java中的Synchronized關鍵字用法

技術 class method state 總結 object oid ack body

巨人大哥談Java中的Synchronized關鍵字用法

認識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上是對於整個類文件有效。

巨人大哥談Java中的Synchronized關鍵字用法