目錄
- 一、基礎使用
- 1.1 不加鎖的代碼實現
- 1.2 加鎖的代碼實現
- 二、實現原理
- 2.1 synchronized 簡介
- 2.2 對象監控器(Monitor)
- 2.3 加鎖過程
- 第一步:判斷 Owner 指向
- 第二步:進入 EntryList 阻塞
- 第三步:主動進入 WaitSet 等待
- 三、鎖升級
- 3.1 對象的內存結構
- 3.2 Mark Word 對象頭
- 3.3 Monitor 重量級鎖
- 3.4 輕量級鎖
- 1)背景:
- 2)加鎖過程:
- 3)解鎖過程:
- 3.5 偏向鎖
- 1)背景:
- 2)加鎖過程:
- 3)輕量級鎖 vs 偏向鎖
- 3.6 總結

一、基礎使用
- 假如有這樣一個場景:20個用戶一起搶10張票。
1.1 不加鎖的代碼實現
public class TicketDemo {// 票總數private int ticketNum = 10;/*** 搶票*/public void getTicket() {if (ticketNum <= 0) {return;}System.out.println(Thread.currentThread().getName() + " 搶到一張票,剩余:" + ticketNum);// 非原子性操作ticketNum--;}/*** 測試:20個人搶一張票*/public static void main(String[] args) {TicketDemo ticketDemo = new TicketDemo();for (int i = 0; i < 20; i++) {new Thread(ticketDemo::getTicket).start();}}
}
執行結果:

可以看到出現了 超賣問題,一共10張票,當20個線程一起搶票就出現有11個人搶到了票。這是因為如果兩個線程同時通過了 if 校驗。

所以我們需要對票數的操作進行加鎖,保證同一時間只有一個線程來檢查和操作票數扣減。
1.2 加鎖的代碼實現
public class TicketDemo {// 鎖private static Object lock = new Object();// 票總數private int ticketNum = 10;/*** 搶票*/public void getTicket() {synchronized (lock) {if