一、基本概念
- 目的:解決多線程并發訪問共享資源時的數據競爭問題,保證原子性、可見性和有序性(JMM內存模型)。
- 性質:可重入鎖(同一線程可重復獲取同一把鎖)、獨占鎖(互斥鎖)。
- JVM級別:由JVM實現,無需手動釋放鎖(編譯器自動生成monitorexit指令)
二、三種使用方式
粒度 | 示例 | 鎖對象 |
---|---|---|
實例方法 | synchronized void method() | 當前實例 (this) |
靜態方法 | synchronized static void method() | 當前類的Class對象(如 Object.class) |
代碼塊 | synchronized(obj) { … } | 指定對象(任意Object) |
三、底層原理(JVM層面)
-
同步代碼塊:通過 monitorenter 和 monitorexit 指令實現(編譯后插入字節碼)。
-
同步方法:方法常量池中設置 ACC_SYNCHRONIZED 標志,調用時隱式獲取鎖。
-
Monitor機制:
-
每個Java對象關聯一個Monitor(管程),包含:
1、 _owner:持有鎖的線程
2、_EntryList:阻塞等待鎖的線程隊列
3、 _WaitSet:調用 wait() 后進入的等待隊列
-
線程通過CAS競爭進入 _owner,失敗則進入 _EntryList 阻塞。
-
四、鎖升級過程(優化重點!)
Java 6后引入自適應自旋鎖、鎖消除、鎖粗化等優化,鎖狀態存儲在對象頭Mark Word中。
升級流程:
1、無鎖:初始狀態
2、偏向鎖(Biased Lock)
-
場景:只有一個線程訪問
-
原理:在Mark Word存儲線程ID,避免CAS操作
3、輕量級鎖(Lightweight Lock)
-
場景:多線程交替執行,無實際競爭
-
原理:通過CAS自旋嘗試獲取鎖(避免線程阻塞)
4、重量級鎖(Heavyweight Lock)
- 場景:多線程競爭激烈
- 原理:競爭失敗線程進入阻塞隊列,依賴操作系統Mutex實現
五、 優缺點
優點 | 缺點 |
---|---|
語法簡單,自動釋放鎖 | 無法中斷等待鎖的線程 |
JVM原生支持,穩定性高 | 非公平鎖(可能導致線程饑餓) |
鎖升級機制優化低競爭場景性能 | 只能綁定一個條件變量(wait/notify) |
高競爭時升級重量級鎖性能下降 |
六、與ReentrantLock對比
特性 | synchronized | ReentrantLock |
---|---|---|
實現 | JVM層面 | JDK API(AQS實現) |
鎖中斷 | ? 不支持 | ? lockInterruptibly() |
公平鎖 | ? 非公平 | ? 可選公平/非公平 |
條件變量 | ? 單條件 | ? 多條件(newCondition()) |
鎖超時 | ? 不支持 | ? tryLock(timeout) |