剛剛開始學習 Java 的時候,一遇到多執行緒的問題就簡單粗暴地使用 synchronized 關鍵字,對於當時的我們來說,synchronized 是多麼的神奇和強大呀!那個時候我們還給 synchronized 起了一個名字“同步”,它成了我們解決多執行緒問題百試不爽的良藥。
後來隨著學習的深入,我們知道 synchronized 是一個重量級鎖,相對於 Lock,顯得非常笨重,以至於我們認為它不是那麼的高效而慢慢摒棄它。隨著 Javs 6 對 synchronized 進行了各種優化,synchronized 並不會顯得那麼笨重了。
本節我們重點討論一下 synchronized 關鍵字的實現機制、Java 對 synchronized 進行了什麼優化、鎖優化機制、鎖的儲存結構和升級過程。
Java synchronized 實現原理
synchronized 可以保證方法或者程式碼塊在執行時,同一時刻只有一個方法可以進入到臨界區,同時它還可以保證共用變數的記憶體可見性。
Java 中每一個物件都可以作為鎖,這是 synchronized 實現同步的基礎:
-
普通同步方法,鎖是當前範例物件;
-
靜態同步方法,鎖是當前類的 class 物件;
-
同步方法塊,鎖是括號裡面的物件。
當一個執行緒存取同步程式碼塊時,它首先是需要得到鎖才能執行同步程式碼,當退出或者丟擲異常時必須要釋放鎖,那麼它是如何來實現這個機制的呢?我們先來看下面一段 Java 程式碼:
public class SynchronizedTest {
public synchronized void test1(){
}
public void test2(){
synchronized (this){
}
}
}
為了分析 synchronize 的實現,我們需要利用 javap 工具檢視生成的 .class檔案(位元組碼檔案)資訊: