Java并發(fā)編程之ReentrantLock的實(shí)現(xiàn)示例
一、可中斷鎖
1. 核心方法:lockInterruptibly()
- 作用:允許線程在等待鎖的過程中響應(yīng)中斷請(qǐng)求。
- 適用場(chǎng)景:需要支持任務(wù)取消或中斷的同步操作(如用戶手動(dòng)取消長(zhǎng)時(shí)間等待的任務(wù))。
2. 代碼示例
ReentrantLock lock = new ReentrantLock();
Thread thread = new Thread(() -> {
try {
lock.lockInterruptibly(); // 可中斷獲取鎖
try {
System.out.println("線程獲取鎖并執(zhí)行任務(wù)");
Thread.sleep(5000); // 模擬耗時(shí)操作
} finally {
lock.unlock();
}
} catch (InterruptedException e) {
System.out.println("線程被中斷,放棄獲取鎖");
}
});
lock.lock(); // 主線程先獲取鎖
try {
thread.start();
Thread.sleep(1000); // 確保子線程開始等待鎖
thread.interrupt(); // 中斷子線程
} finally {
lock.unlock();
}
3. 行為分析
- 未中斷時(shí):線程正常獲取鎖并執(zhí)行任務(wù)。
- 中斷時(shí):拋出
InterruptedException,線程退出等待隊(duì)列。
二、鎖超時(shí)
1. 核心方法:tryLock()
無參方法:
boolean tryLock()
立即嘗試獲取鎖,成功返回true,失敗返回false。帶超時(shí)方法:
boolean tryLock(long timeout, TimeUnit unit)
在指定時(shí)間內(nèi)嘗試獲取鎖,超時(shí)后放棄。
2. 代碼示例:避免死鎖
ReentrantLock lockA = new ReentrantLock();
ReentrantLock lockB = new ReentrantLock();
Thread thread1 = new Thread(() -> {
try {
if (lockA.tryLock(1, TimeUnit.SECONDS)) { // 嘗試獲取lockA
try {
if (lockB.tryLock(1, TimeUnit.SECONDS)) { // 嘗試獲取lockB
System.out.println("Thread1完成任務(wù)");
}
} finally {
if (lockB.isHeldByCurrentThread()) lockB.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lockA.isHeldByCurrentThread()) lockA.unlock();
}
});
Thread thread2 = new Thread(() -> { /* 類似邏輯,先嘗試lockB再lockA */ });
thread1.start();
thread2.start();
3. 應(yīng)用場(chǎng)景
- 死鎖預(yù)防:通過超時(shí)放棄鎖請(qǐng)求,打破循環(huán)等待。
- 響應(yīng)性優(yōu)化:避免線程長(zhǎng)時(shí)間阻塞影響系統(tǒng)響應(yīng)速度。
三、條件變量
1. 核心機(jī)制
- 創(chuàng)建條件變量:
Condition condition = lock.newCondition(); - 等待條件:
condition.await(); - 喚醒線程:
condition.signal()或condition.signalAll()
2. 代碼示例:生產(chǎn)者-消費(fèi)者模型
ReentrantLock lock = new ReentrantLock();
Condition notEmpty = lock.newCondition(); // 非空條件
Condition notFull = lock.newCondition(); // 非滿條件
Queue<Integer> queue = new LinkedList<>();
int maxSize = 10;
// 生產(chǎn)者
new Thread(() -> {
lock.lock();
try {
while (queue.size() == maxSize) {
notFull.await(); // 等待隊(duì)列非滿
}
queue.add(1);
notEmpty.signal(); // 通知消費(fèi)者
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
// 消費(fèi)者
new Thread(() -> {
lock.lock();
try {
while (queue.isEmpty()) {
notEmpty.await(); // 等待隊(duì)列非空
}
queue.poll();
notFull.signal(); // 通知生產(chǎn)者
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
3. 優(yōu)勢(shì)對(duì)比wait()/notify()
| 特性 | Condition | wait()/notify() |
|---|---|---|
| 多條件支持 | ? 可創(chuàng)建多個(gè)條件變量 | ? 每個(gè)對(duì)象僅一個(gè)等待隊(duì)列 |
| 精準(zhǔn)喚醒 | ? signal() 喚醒指定條件隊(duì)列的線程 | ? notify() 隨機(jī)喚醒 |
四、關(guān)鍵注意事項(xiàng)
1. 鎖釋放
- 必須手動(dòng)釋放:lock.unlock() 需放在 finally 塊中確保執(zhí)行。
- 重入次數(shù)匹配:加鎖和解鎖次數(shù)必須一致,否則導(dǎo)致鎖無法釋放。
2. 中斷處理
- 響應(yīng)中斷:lockInterruptibly() 和 await() 需捕獲 InterruptedException。
- 恢復(fù)中斷狀態(tài):調(diào)用 Thread.currentThread().interrupt() 保留中斷標(biāo)志。
到此這篇關(guān)于Java并發(fā)編程之ReentrantLock的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Java ReentrantLock內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Data JPA 之 JpaRepository的使用
這篇文章主要介紹了Spring Data JPA 之 JpaRepository的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
使用Java和PostgreSQL存儲(chǔ)向量數(shù)據(jù)的實(shí)現(xiàn)指南
在當(dāng)今的數(shù)字化時(shí)代,數(shù)據(jù)存儲(chǔ)的方式和技術(shù)正變得越來越復(fù)雜和多樣化,隨著機(jī)器學(xué)習(xí)和數(shù)據(jù)科學(xué)的發(fā)展,向量數(shù)據(jù)的存儲(chǔ)和管理變得尤為重要,本文將詳細(xì)介紹如何使用 Java 和 PostgreSQL 數(shù)據(jù)庫(kù)來存儲(chǔ)向量數(shù)據(jù),需要的朋友可以參考下2024-09-09
如何在springboot項(xiàng)目中自定義404頁面
今天點(diǎn)擊菜單的時(shí)候不小心點(diǎn)開了一個(gè)不存在的頁面,然后看到瀏覽器給的一個(gè)默認(rèn)的404頁面,這篇文章主要介紹了如何在springboot項(xiàng)目中自定義404頁面,需要的朋友可以參考下2024-05-05
Java如何自定義類數(shù)組的創(chuàng)建和初始化
這篇文章主要介紹了Java如何自定義類數(shù)組的創(chuàng)建和初始化,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
MyBatis 關(guān)聯(lián)查詢延遲加載實(shí)戰(zhàn)案例
本文介紹了MyBatis開發(fā)中一對(duì)多、一對(duì)一關(guān)聯(lián)查詢的配置方法,重點(diǎn)講解了resultMap、association、collection等核心標(biāo)簽的使用場(chǎng)景和用語法,并詳細(xì)解釋了延遲加載(fetchType屬性)的配置方法和執(zhí)行流程,最后總結(jié)了單表查詢、一對(duì)一關(guān)聯(lián)和一對(duì)多關(guān)聯(lián)的配置方法和注意事項(xiàng)2026-05-05
Java如何把數(shù)組轉(zhuǎn)換為ArrayList
這篇文章主要介紹了Java如何把數(shù)組轉(zhuǎn)換為ArrayList,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01
JVM入門之JVM內(nèi)存結(jié)構(gòu)內(nèi)容詳解
這篇文章主要介紹了JVM入門之JVM內(nèi)存結(jié)構(gòu)內(nèi)容詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09

