1.說一說自己對於 synchronized 關鍵字的瞭解
synchronized是解決多執行緒之間訪問資源的同步性,synchronized關鍵字可以保證被他修飾的資源在任何時刻只有一個執行緒訪問。
在Java6之前,synchronized是重量鎖,在其之後官方從JVM層面對synchronized進行了非常大的優化。
2. 說說自己是怎麼使用 synchronized 關鍵字
- 修飾例項方法
- 修飾靜態方法
- 修飾程式碼塊
- 對於普通同步方法,鎖是當前例項物件。
- 對於靜態同步方法,鎖是當前類的Class物件。
- 對於同步方法塊,鎖是Synchonized括號裡配置的物件
3. 講一下 synchronized 關鍵字的底層原理
首先先寫一個synchronized的同步語句塊程式碼,進行編譯:
package com.JUC;
/**
* @author xbhog
* @date 2022/2/15
* @apiNote
* @title 雙重校驗鎖實現物件單例(執行緒安全)
*/
public class Singleton {
private static volatile Singleton uniqueInstance;
public Singleton() {
}
public static Singleton getUniqueInstance(){
//先判斷物件是否已經例項過,沒有例項化過才進入加鎖程式碼
if(uniqueInstance == null){
//類物件加鎖
synchronized (Singleton.class){
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
public static void main(String[] args) {
}
}
進入其編譯的資料夾中,然後執行分析命令:
javap -c -s -v -l Singleton.class
命令解釋:
一般常用的是-v -l -c三個選項。
javap -v classxx,不僅會輸出行號、本地變數表資訊、反編譯彙編程式碼,還會輸出當前類用到的常量池等資訊。
javap -l 會輸出行號和本地變數表資訊。
javap -c 會對當前class位元組碼進行反編譯生成彙編程式碼。
javap-s 輸出內部型別簽名
更多內容可以檢視該部落格:點選
通過上圖可以看到:synchronized同步語句塊的實現使用是monitorenter和monitorexit指令。其中
monitorenter
指令指向同步程式碼塊的開始位置,monitorexit
指令則指明同步程式碼塊的結束位置。
任意執行緒對Object(Object由synchronized保護)的訪問,首先要獲得Object的監視器。如果獲取失敗(鎖的計數器不為 0),執行緒進入同步佇列,執行緒狀態變為BLOCKED。當訪問Object的前驅(獲得了鎖的執行緒)釋放了鎖(鎖的計數器為0),則該釋放操作喚醒阻塞在同步佇列中的執行緒,使其重新嘗試對監視器的獲取。
具體詳情:點選
寫一個synchronized的修飾方法程式碼,進行編譯:
package com.JUC;
/**
* @author xbhog
* @date 2022/2/15
* @title: synchronized 修飾方法的情況
*/
public class SynchronizedMethod {
public synchronized void method() {
System.out.println("synchronized 方法");
}
}
synchronized修飾的方法沒有monitorenter和monitorexit指令,但是使用的ACC_SYNCHRONIZED
標識,該標識指明瞭該方法是一個同步方法。
synchronized修飾程式碼塊和修飾方法本質都是使用物件監視器獲取的。
4. 談談ReentrantLock
- 實現等待可中斷
- 可實現公平鎖
- 可實現選擇性通知:需要與Condition使用,點選進入
詳情請看:點選