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使用,點擊進入
詳情請看:點擊