Synchronized 底層原理與 Lock 的核心區別
前言
圖片
在Java并發編程中,synchronized和Lock是實現線程同步的兩大核心機制。理解它們的底層原理和核心區別,對于編寫高效、安全的并發代碼至關重要。
synchronized 底層原理
對象頭與 Mark Word
在Java中,每個對象都有一個 對象頭(Object Header),其中包含Mark Word和類型指針。Mark Word是實現synchronized的關鍵,它存儲了對象的鎖狀態、HashCode、GC年齡等信息。
不同鎖狀態下,Mark Word 的結構不同:
- 無鎖狀態:存儲對象的HashCode和GC年齡。
- 偏向鎖狀態:存儲偏向線程ID,表明該對象長期被某一線程獨占。
- 輕量級鎖狀態:存儲指向線程棧中鎖記錄的指針。
- 重量級鎖狀態:存儲指向Monitor鎖的指針。
Monitor 鎖機制
當synchronized升級到重量級鎖時,會依賴Monitor鎖(也稱為管程)。Monitor 是一種同步工具,本質是操作系統提供的互斥鎖(Mutex),通過控制線程的阻塞與喚醒實現同步。
Monitor的核心結構包括:
- Owner:指向當前持有鎖的線程。
- EntryList:存儲等待獲取鎖的線程隊列。
- WaitSet:存儲調用wait()方法后釋放鎖的線程隊列。
線程獲取Monitor鎖的流程:
- 線程嘗試獲取鎖,若Owner為空,則直接占有鎖并將Owner指向自己。
- 若鎖已被其他線程占有,則當前線程進入EntryList阻塞等待。
- 當Owner線程釋放鎖時,會喚醒EntryList中的線程重新競爭鎖。
鎖升級策略
為減少鎖競爭帶來的性能損耗,JVM引入了 鎖升級 機制,從低開銷的鎖狀態逐步升級到高開銷狀態:
- 偏向鎖:適用于單線程重復獲取鎖的場景。線程首次獲取鎖時,Mark Word記錄線程ID,后續該線程可直接獲取鎖,無需競爭。
- 輕量級鎖:當有其他線程競爭鎖時,偏向鎖升級為輕量級鎖。線程通過CAS操作將Mark Word中的鎖記錄指針指向自己的棧幀,避免進入內核態阻塞。
- 重量級鎖:若輕量級鎖競爭激烈(多線程頻繁CAS失敗),則升級為重量級鎖。此時依賴Monitor鎖,線程會進入內核態阻塞,性能開銷較大。
Lock 的核心實現
Lock是Java 5引入的接口(位于java.util.concurrent.locks包),通過API層面實現線程同步,其核心實現類為ReentrantLock。Lock的底層依賴 AQS(AbstractQueuedSynchronizer)框架。
AQS 核心原理
AQS是并發工具的基礎框架,通過同步狀態和雙向阻塞隊列實現鎖的獲取與釋放:
- 同步狀態(state):用volatile int變量存儲鎖的狀態(0表示未鎖定,大于0表示已鎖定,支持可重入)。
- 雙向阻塞隊列:存儲等待獲取鎖的線程,通過FIFO原則保證線程公平性(可選)。
線程獲取鎖的流程(以 ReentrantLock 為例):
- 調用lock()方法時,線程嘗試通過CAS操作修改state:
若state=0,修改為1并成功獲取鎖。
若state>0且當前線程是鎖持有者(可重入),則state加1。
若獲取失敗,線程進入雙向隊列阻塞等待。
- 調用unlock()方法時,線程減少state值:
若state減為0,釋放鎖并喚醒隊列中的線程。
Lock 的核心特性
Lock接口定義了比synchronized更靈活的同步操作,核心方法包括:
- lock():獲取鎖,若未獲取則阻塞。
- lockInterruptibly():可中斷地獲取鎖,允許線程響應中斷。
- tryLock():嘗試非阻塞獲取鎖,成功返回true。
- tryLock(long time, TimeUnit unit):超時獲取鎖。
- unlock():釋放鎖(需手動調用,通常配合try-finally)。
- newCondition():創建條件變量,實現線程間的精細化通信。
synchronized 與 Lock 的核心區別
對比維度 | synchronized | Lock |
實現層面 | JVM 內置關鍵字,依賴底層字節碼指令(monitorenter/monitorexit) | Java 類庫接口,基于 AQS 框架實現 |
鎖的獲取與釋放 | 自動獲取與釋放(由 JVM 控制) | 手動獲取與釋放(需顯式調用 lock()/unlock(),建議用 try-finally 確保釋放) |
可中斷性 | 不可中斷,一旦阻塞無法響應中斷 | 可中斷(lockInterruptibly()) |
超時獲取 | 不支持 | 支持(tryLock(long time, TimeUnit unit)) |
公平性 | 非公平鎖(無法設置) | 可選擇公平鎖或非公平鎖(構造函數參數控制) |
條件變量 | 僅支持一個條件變量(通過 wait()/notify() 實現) | 支持多個條件變量(newCondition() 創建) |
性能 | 低競爭場景下性能優異(鎖升級優化);高競爭場景下略遜于 Lock | 高競爭場景下性能更穩定(減少內核態阻塞開銷) |
可重入性 | 支持(同一線程可重復獲取鎖) | 支持(ReentrantLock 是可重入鎖) |
使用案例
synchronized 使用案例
同步方法:
public class SynchronizedMethodExample {
private int count = 0;
// 同步實例方法,鎖為當前對象
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
SynchronizedMethodExample example = new SynchronizedMethodExample();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Count: " + example.getCount()); // 輸出 2000
}
}同步代碼塊:
public class SynchronizedBlockExample {
private int count = 0;
private Object lock = new Object();
public void increment() {
// 同步代碼塊,鎖為lock對象
synchronized (lock) {
count++;
}
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
SynchronizedBlockExample example = new SynchronizedBlockExample();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Count: " + example.getCount()); // 輸出 2000
}
}Lock 使用案例
基本使用:
public class LockBasicExample {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
LockBasicExample example = new LockBasicExample();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Count: " + example.getCount()); // 輸出 2000
}
}可中斷鎖:
public class InterruptibleLockExample {
private Lock lock = new ReentrantLock();
public void doTask() {
try {
// 可中斷地獲取鎖
lock.lockInterruptibly();
try {
System.out.println(Thread.currentThread().getName() + " 獲取到鎖,開始執行任務");
Thread.sleep(5000);
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + " 釋放鎖");
}
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 被中斷,未能獲取鎖");
}
}
public static void main(String[] args) throws InterruptedException {
InterruptibleLockExample example = new InterruptibleLockExample();
Thread thread1 = new Thread(example::doTask, "Thread-1");
Thread thread2 = new Thread(example::doTask, "Thread-2");
thread1.start();
Thread.sleep(1000); // 確保thread1先獲取到鎖
thread2.start();
Thread.sleep(1000);
thread2.interrupt(); // 中斷thread2
}
}超時獲取鎖:
public class TimeoutLockExample {
private Lock lock = new ReentrantLock();
public void doTask() {
try {
// 超時獲取鎖,最多等待2秒
if (lock.tryLock(2, TimeUnit.SECONDS)) {
try {
System.out.println(Thread.currentThread().getName() + " 獲取到鎖,開始執行任務");
Thread.sleep(3000);
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + " 釋放鎖");
}
} else {
System.out.println(Thread.currentThread().getName() + " 超時未獲取到鎖");
}
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 被中斷");
}
}
public static void main(String[] args) {
TimeoutLockExample example = new TimeoutLockExample();
Thread thread1 = new Thread(example::doTask, "Thread-1");
Thread thread2 = new Thread(example::doTask, "Thread-2");
thread1.start();
thread2.start();
}
}多條件變量:
public class MultiConditionExample {
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private boolean flag1 = false;
private boolean flag2 = false;
public void waitForCondition1() throws InterruptedException {
lock.lock();
try {
while (!flag1) {
condition1.await();
}
System.out.println(Thread.currentThread().getName() + " 條件1滿足,執行操作");
} finally {
lock.unlock();
}
}
public void waitForCondition2() throws InterruptedException {
lock.lock();
try {
while (!flag2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName() + " 條件2滿足,執行操作");
} finally {
lock.unlock();
}
}
public void signalCondition1() {
lock.lock();
try {
flag1 = true;
condition1.signal();
System.out.println("喚醒等待條件1的線程");
} finally {
lock.unlock();
}
}
public void signalCondition2() {
lock.lock();
try {
flag2 = true;
condition2.signal();
System.out.println("喚醒等待條件2的線程");
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
MultiConditionExample example = new MultiConditionExample();
Thread threadA = new Thread(() -> {
try {
example.waitForCondition1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Thread-A");
Thread threadB = new Thread(() -> {
try {
example.waitForCondition2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Thread-B");
threadA.start();
threadB.start();
Thread.sleep(1000);
example.signalCondition1();
Thread.sleep(1000);
example.signalCondition2();
}
}





























