Java并發(fā)鎖機(jī)制知識(shí)總結(jié)(最新整理)
并發(fā)鎖機(jī)制知識(shí)總結(jié)
Java 的鎖機(jī)制是并發(fā)編程的核心,用于解決多線程共享資源競(jìng)爭(zhēng)問(wèn)題,保證數(shù)據(jù)一致性和線程安全。Java 提供了內(nèi)置鎖(synchronized)、顯式鎖(Lock 接口) 等多種鎖實(shí)現(xiàn),同時(shí)衍生出偏向鎖、輕量級(jí)鎖、重量級(jí)鎖等優(yōu)化機(jī)制,以及可重入鎖、公平鎖、讀寫(xiě)鎖等功能分類(lèi)。
一、鎖的核心作用
- 互斥性:同一時(shí)間只有一個(gè)線程能持有鎖,訪問(wèn)共享資源(解決 “競(jìng)態(tài)條件”)。
- 可見(jiàn)性:持有鎖的線程修改共享資源后,釋放鎖時(shí)會(huì)將修改同步到主內(nèi)存;其他線程獲取鎖時(shí)會(huì)從主內(nèi)存讀取最新值(避免 “緩存一致性問(wèn)題”)。
- 有序性:禁止指令重排序(避免多線程下的 “指令重排導(dǎo)致的邏輯錯(cuò)亂”)。
二、Java 鎖的分類(lèi)
(一)按實(shí)現(xiàn)方式:內(nèi)置鎖 vs 顯式鎖
1. 內(nèi)置鎖:synchronized(JVM 層面實(shí)現(xiàn))
synchronized 是 Java 原生的隱式鎖,基于 對(duì)象監(jiān)視器(Monitor) 實(shí)現(xiàn),無(wú)需手動(dòng)釋放,簡(jiǎn)單易用、線程安全。
(1)使用場(chǎng)景
(2)示例代碼
public class SynchronizedDemo {
// 1. 實(shí)例方法鎖(鎖:this)
public synchronized void method1() {
// 共享資源操作
}
// 2. 靜態(tài)方法鎖(鎖:SynchronizedDemo.class)
public static synchronized void method2() {
// 共享資源操作
}
// 3. 代碼塊鎖(鎖:自定義對(duì)象)
private final Object lock = new Object();
public void method3() {
synchronized (lock) {
// 共享資源操作
}
}
}(3)核心特性
(4)JVM 優(yōu)化:鎖升級(jí)(無(wú)鎖 → 偏向鎖 → 輕量級(jí)鎖 → 重量級(jí)鎖)
為了平衡性能和并發(fā)安全,JVM 對(duì) synchronized 進(jìn)行了鎖升級(jí)優(yōu)化(從低開(kāi)銷(xiāo)到高開(kāi)銷(xiāo)逐步過(guò)渡):
鎖升級(jí)是不可逆的(一旦升級(jí)為重量級(jí)鎖,不會(huì)降級(jí))。
2. 顯式鎖:Lock 接口(Java 代碼層面實(shí)現(xiàn))
java.util.concurrent.locks.Lock 是 JDK 1.5 引入的顯式鎖,提供比 synchronized 更靈活的功能(如可中斷、超時(shí)獲取、公平鎖等),但需手動(dòng)釋放鎖(否則會(huì)導(dǎo)致死鎖)。
(1)核心方法
| 方法 | 作用 |
|---|---|
lock() | 獲取鎖(阻塞,不可中斷) |
lockInterruptibly() | 獲取鎖(可被中斷,拋出 InterruptedException) |
tryLock() | 嘗試獲取鎖(非阻塞,成功返回 true,失敗返回 false) |
tryLock(long time, TimeUnit unit) | 超時(shí)獲取鎖(超時(shí)未獲取則返回 false) |
unlock() | 釋放鎖(必須在 finally 中調(diào)用) |
newCondition() | 創(chuàng)建條件變量(實(shí)現(xiàn)線程等待 / 喚醒) |
(2)常用實(shí)現(xiàn)類(lèi)
(3)示例代碼(ReentrantLock)
import java.util.concurrent.locks.ReentrantLock;
public class LockDemo {
// 創(chuàng)建非公平鎖(默認(rèn)),若要公平鎖:new ReentrantLock(true)
private final ReentrantLock lock = new ReentrantLock();
public void method() {
// 1. 獲取鎖(必須手動(dòng)獲取)
lock.lock();
try {
// 共享資源操作
} finally {
// 2. 釋放鎖(必須在 finally 中釋放,避免鎖泄漏)
lock.unlock();
}
}
// 可中斷獲取鎖示例
public void interruptibleMethod() throws InterruptedException {
lock.lockInterruptibly(); // 線程可被中斷
try {
// 共享資源操作
} finally {
lock.unlock();
}
}
}(4)核心特性
(二)按功能特性分類(lèi)
1. 可重入鎖 vs 不可重入鎖
2. 公平鎖 vs 非公平鎖
3. 讀寫(xiě)鎖(ReentrantReadWriteLock)
針對(duì) “讀多寫(xiě)少” 場(chǎng)景優(yōu)化,分離讀鎖(共享鎖) 和寫(xiě)鎖(排他鎖):
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
private int data;
// 讀操作(共享鎖)
public int readData() {
readLock.lock();
try {
return data;
} finally {
readLock.unlock();
}
}
// 寫(xiě)操作(排他鎖)
public void writeData(int value) {
writeLock.lock();
try {
data = value;
} finally {
writeLock.unlock();
}
}
}4. 樂(lè)觀鎖 vs 悲觀鎖
(三)其他特殊鎖
1. 自旋鎖(SpinLock)
線程獲取鎖失敗時(shí),不立即阻塞,而是循環(huán)(自旋)嘗試獲取鎖(避免線程上下文切換開(kāi)銷(xiāo))。
2. 偏向鎖 / 輕量級(jí)鎖 / 重量級(jí)鎖(JVM 層面的鎖優(yōu)化)
見(jiàn)前文 synchronized 的鎖升級(jí)機(jī)制,核心是 “按需升級(jí)”,平衡性能和并發(fā)安全。
3. StampedLock(樂(lè)觀讀鎖)
JDK 1.8 引入,性能優(yōu)于 ReentrantReadWriteLock,支持三種模式:
三、synchronized vs ReentrantLock 對(duì)比
| 特性 | synchronized | ReentrantLock |
|---|---|---|
| 實(shí)現(xiàn)層面 | JVM 層面(底層是 Monitor) | Java 代碼層面(AQS 框架) |
| 可重入性 | 支持 | 支持 |
| 公平性 | 僅非公平鎖 | 公平 / 非公平可選 |
| 可中斷性 | 不支持 | 支持(lockInterruptibly ()) |
| 超時(shí)獲取 | 不支持 | 支持(tryLock (time)) |
| 條件變量 | 僅一個(gè)(wait ()/notify ()) | 多個(gè)(newCondition ()) |
| 鎖釋放 | 自動(dòng)釋放(退出同步塊 / 方法) | 手動(dòng)釋放(必須在 finally 中 unlock ()) |
| 性能 | JDK 1.6 后優(yōu)化(鎖升級(jí)),性能接近 ReentrantLock | 高(靈活控制) |
| 適用場(chǎng)景 | 簡(jiǎn)單場(chǎng)景(無(wú)需復(fù)雜功能) | 復(fù)雜場(chǎng)景(需中斷、超時(shí)、公平鎖等) |
四、鎖的使用注意事項(xiàng)
總結(jié)
Java 鎖機(jī)制的核心是解決共享資源競(jìng)爭(zhēng),提供了從簡(jiǎn)單到復(fù)雜的多種實(shí)現(xiàn):
使用鎖時(shí)需平衡線程安全和性能,避免死鎖、鎖粒度過(guò)大等問(wèn)題,根據(jù)實(shí)際場(chǎng)景選擇合適的鎖類(lèi)型。
最后祝各位開(kāi)發(fā)者工作順利,萬(wàn)事如意。
- 修飾實(shí)例方法:鎖是當(dāng)前對(duì)象(
this)。 - 修飾靜態(tài)方法:鎖是當(dāng)前類(lèi)的
Class對(duì)象(全局鎖)。 - 修飾代碼塊:鎖是括號(hào)中的對(duì)象(可自定義鎖對(duì)象,靈活度更高)。
- 可重入:同一線程可多次獲取同一把鎖(避免死鎖,如遞歸調(diào)用 synchronized 方法)。
- 非公平鎖:線程獲取鎖的順序不按請(qǐng)求順序(默認(rèn),性能優(yōu)先)。
- 自動(dòng)釋放:線程退出同步塊 / 方法時(shí),無(wú)論正常退出還是異常退出,鎖都會(huì)自動(dòng)釋放(無(wú)需手動(dòng)處理)。
- 不可中斷:線程獲取鎖時(shí)若被阻塞,只能等待鎖釋放或一直阻塞(無(wú)法主動(dòng)中斷)。
- 無(wú)鎖:無(wú)線程競(jìng)爭(zhēng)時(shí),無(wú)需加鎖(直接執(zhí)行)。
- 偏向鎖:?jiǎn)尉€程重復(fù)獲取鎖時(shí),僅記錄線程 ID(避免 CAS 操作,開(kāi)銷(xiāo)極低)。
- 觸發(fā)條件:只有一個(gè)線程訪問(wèn)同步資源。
- 撤銷(xiāo):當(dāng)有第二個(gè)線程競(jìng)爭(zhēng)時(shí),偏向鎖會(huì)升級(jí)為輕量級(jí)鎖。
- 輕量級(jí)鎖: 多個(gè)線程交替訪問(wèn)鎖(無(wú)激烈競(jìng)爭(zhēng)),通過(guò)CAS(Compare and Swap)嘗試獲取鎖(自旋等待,避免阻塞線程)。
- 自旋次數(shù):默認(rèn) 10 次(可通過(guò)
-XX:PreBlockSpin調(diào)整),自旋失敗則升級(jí)為重量級(jí)鎖。
- 自旋次數(shù):默認(rèn) 10 次(可通過(guò)
- 重量級(jí)鎖:多個(gè)線程激烈競(jìng)爭(zhēng)鎖(自旋無(wú)效),通過(guò)操作系統(tǒng)的 互斥量(Mutex) 實(shí)現(xiàn)(線程會(huì)阻塞,開(kāi)銷(xiāo)最高)。
- ReentrantLock:可重入鎖(最常用),支持公平鎖和非公平鎖(默認(rèn)非公平)。
- ReentrantReadWriteLock:讀寫(xiě)鎖(分離讀鎖和寫(xiě)鎖,提高讀多寫(xiě)少場(chǎng)景的并發(fā)性能)。
- StampedLock:JDK 1.8 引入的樂(lè)觀讀鎖(性能優(yōu)于讀寫(xiě)鎖,支持樂(lè)觀讀、寫(xiě)鎖、悲觀讀鎖)。
- 可重入:與
synchronized一致,同一線程可多次獲取鎖(鎖計(jì)數(shù)器遞增,釋放時(shí)遞減至 0 才釋放)。 - 公平 / 非公平可選:構(gòu)造函數(shù)傳入
true則為公平鎖(按線程請(qǐng)求順序分配鎖,性能略低),默認(rèn)非公平鎖(性能優(yōu)先)。 - 可中斷:支持
lockInterruptibly()中斷阻塞中的線程(避免無(wú)限等待)。 - 超時(shí)獲取:通過(guò)
tryLock(time)避免線程永久阻塞。 - 條件變量:通過(guò)
newCondition()創(chuàng)建多個(gè)條件變量(比synchronized的wait()/notify()更靈活,可精準(zhǔn)喚醒特定線程)。 可重入鎖:同一線程可多次獲取同一把鎖(如synchronized、ReentrantLock),避免遞歸調(diào)用或嵌套同步時(shí)的死鎖。
- 原理:鎖內(nèi)部維護(hù)一個(gè) “線程持有計(jì)數(shù)”,線程首次獲取時(shí)計(jì)數(shù)為 1,再次獲取時(shí)計(jì)數(shù)遞增,釋放時(shí)計(jì)數(shù)遞減,計(jì)數(shù)為 0 時(shí)鎖釋放。
不可重入鎖:同一線程無(wú)法多次獲取同一把鎖(如簡(jiǎn)單的
SpinLock實(shí)現(xiàn)),容易導(dǎo)致死鎖,極少使用。- 公平鎖:線程獲取鎖的順序嚴(yán)格按照 “請(qǐng)求順序”(FIFO),不會(huì)出現(xiàn)饑餓(每個(gè)線程都能最終獲取鎖)。
- 實(shí)現(xiàn):維護(hù)一個(gè)等待隊(duì)列,新線程需加入隊(duì)列尾部,僅當(dāng)隊(duì)列頭部線程才能獲取鎖。
- 缺點(diǎn):性能較低(頻繁切換線程上下文)。
- 非公平鎖:線程獲取鎖時(shí)不按請(qǐng)求順序,允許 “插隊(duì)”(剛釋放鎖的線程可能再次獲取鎖,減少上下文切換)。
- 優(yōu)點(diǎn):性能更高(默認(rèn)選擇,如
synchronized、ReentrantLock默認(rèn))。 - 缺點(diǎn):可能導(dǎo)致部分線程長(zhǎng)期無(wú)法獲取鎖(饑餓)。
- 優(yōu)點(diǎn):性能更高(默認(rèn)選擇,如
- 讀鎖(共享鎖):多個(gè)線程可同時(shí)獲取讀鎖(讀操作不互斥)。
- 寫(xiě)鎖(排他鎖):僅一個(gè)線程可獲取寫(xiě)鎖(寫(xiě)操作與讀 / 寫(xiě)操作互斥)。
- 核心規(guī)則:讀鎖持有期間,寫(xiě)鎖無(wú)法獲??;寫(xiě)鎖持有期間,讀鎖和寫(xiě)鎖均無(wú)法獲取。
- 示例代碼:
- 悲觀鎖:認(rèn)為并發(fā)競(jìng)爭(zhēng)必然發(fā)生,每次訪問(wèn)共享資源都先加鎖(如synchronized、ReentrantLock)。
- 優(yōu)點(diǎn):簡(jiǎn)單可靠,適合寫(xiě)操作多的場(chǎng)景。
- 缺點(diǎn):阻塞線程,性能開(kāi)銷(xiāo)高。
- 樂(lè)觀鎖:認(rèn)為并發(fā)競(jìng)爭(zhēng)很少發(fā)生,不加鎖直接訪問(wèn)資源,僅在修改時(shí)通過(guò) CAS 驗(yàn)證是否有沖突(沖突則重試)。
- 實(shí)現(xiàn):
AtomicInteger(基于 CAS)、StampedLock(樂(lè)觀讀模式)、數(shù)據(jù)庫(kù)的版本號(hào)機(jī)制。 - 優(yōu)點(diǎn):非阻塞,性能高,適合讀操作多的場(chǎng)景。
- 缺點(diǎn):存在 “ABA 問(wèn)題”(可通過(guò)版本號(hào) / 時(shí)間戳解決),重試次數(shù)過(guò)多會(huì)消耗 CPU。
- 實(shí)現(xiàn):
- 適用場(chǎng)景:鎖持有時(shí)間短、并發(fā)度低的場(chǎng)景(如 JVM 輕量級(jí)鎖的自旋階段)。
- 缺點(diǎn):自旋期間占用 CPU,若鎖持有時(shí)間長(zhǎng),會(huì)浪費(fèi) CPU 資源。
- 樂(lè)觀讀模式:無(wú)鎖訪問(wèn),讀取后驗(yàn)證版本號(hào)(無(wú)沖突則成功,有沖突則升級(jí)為悲觀讀鎖)。
- 悲觀讀模式:共享鎖(類(lèi)似讀寫(xiě)鎖的讀鎖)。
- 寫(xiě)模式:排他鎖(類(lèi)似讀寫(xiě)鎖的寫(xiě)鎖)。
- 優(yōu)點(diǎn):樂(lè)觀讀模式下無(wú)鎖競(jìng)爭(zhēng),性能極高;缺點(diǎn):不支持可重入,使用復(fù)雜。
- 避免死鎖:
- 手動(dòng)釋放鎖(ReentrantLock 必須在 finally 中 unlock ())。
- 避免嵌套鎖(或保證嵌套鎖的獲取順序一致)。
- 避免長(zhǎng)時(shí)間持有鎖(減少鎖競(jìng)爭(zhēng))。
- 選擇合適的鎖類(lèi)型:
- 讀多寫(xiě)少:用
ReentrantReadWriteLock或StampedLock。 - 簡(jiǎn)單場(chǎng)景:用
synchronized(無(wú)需手動(dòng)管理鎖)。 - 復(fù)雜場(chǎng)景(中斷、超時(shí)、公平鎖):用
ReentrantLock。
- 讀多寫(xiě)少:用
- 減少鎖粒度:
- 避免鎖覆蓋整個(gè)方法(僅對(duì)共享資源的操作加鎖,如 synchronized 代碼塊而非方法)。
- 示例:用
synchronized (lock)替代synchronized method()(僅鎖定關(guān)鍵代碼)。
- 避免鎖競(jìng)爭(zhēng):
- 無(wú)狀態(tài)對(duì)象無(wú)需加鎖(無(wú)共享資源)。
- 共享資源盡量設(shè)計(jì)為不可變(如
String、Integer)。 - 用局部變量替代共享變量(線程私有,無(wú)需鎖)。
- 基礎(chǔ)場(chǎng)景:優(yōu)先使用
synchronized(簡(jiǎn)單、安全、JVM 優(yōu)化充分)。 - 復(fù)雜場(chǎng)景:使用
ReentrantLock(可中斷、超時(shí)、公平鎖)或ReentrantReadWriteLock(讀多寫(xiě)少)。 - 性能優(yōu)化:利用 JVM 鎖升級(jí)(synchronized)、樂(lè)觀鎖(StampedLock、Atomic 類(lèi))減少鎖開(kāi)銷(xiāo)。
到此這篇關(guān)于Java-并發(fā)鎖機(jī)制知識(shí)總結(jié)的文章就介紹到這了,更多相關(guān)Java并發(fā)鎖機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java微信公眾平臺(tái)開(kāi)發(fā)(1) 接入微信公眾平臺(tái)
這篇文章主要為大家詳細(xì)介紹了Java微信公眾平臺(tái)開(kāi)發(fā)第一步,接入微信公眾平臺(tái),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
Java RestTemplate post請(qǐng)求參數(shù)問(wèn)題及解決
作者解決了用JavaRestTemplate進(jìn)行POST請(qǐng)求時(shí)遇到的參數(shù)傳遞問(wèn)題,發(fā)現(xiàn)使用MultiValueMap比Map更合適,同時(shí)強(qiáng)調(diào)了請(qǐng)求頭的數(shù)據(jù)類(lèi)型和URL的占位符在GET請(qǐng)求中如何正確使用2025-12-12
Java使用Fastjson2處理JSON字段大小寫(xiě)不一致的優(yōu)雅方案
這篇文章主要為大家詳細(xì)介紹了Java使用Fastjson2處理JSON字段大小寫(xiě)不一致的優(yōu)雅方案,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2026-04-04

