Java線程死鎖的問題解決
1. 死鎖案例
死鎖:線程之間互相持有對(duì)方的鎖,并且等待獲取對(duì)方持有的鎖。
案例如下:我這里直接寫的service層代碼,沒寫測(cè)試類(測(cè)試類直接調(diào)用deadLockTest()方法)。
package cn.sh.tools.service.component.lock;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
* @Description
* @Classname LockComponent
* @Date 2023/4/28
* @Author sh
**/
@Component
@Slf4j
public class LockComponent {
// 記得在 yml文件中配置線程池相關(guān)參數(shù)(核心線程數(shù)、工作隊(duì)列大小、最大線程數(shù))。
@Resource(name = "applicationTaskExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
// 入?yún)reateThreadNum:要?jiǎng)?chuàng)建的線程數(shù)。盡量設(shè)置個(gè)十幾二十個(gè),設(shè)置的太小可能程序執(zhí)行太快就發(fā)生不了死鎖。
public void deadlockTest(int createThreadNum) {
// 計(jì)數(shù)器
CountDownLatch sunCdl = new CountDownLatch(createThreadNum);
// 1- 填充數(shù)據(jù)
List<DeadLockObj> deadLockObjList = new ArrayList<>(createThreadNum);
/**
* for循環(huán) 創(chuàng)建DeadLockObj對(duì)象,這里只創(chuàng)建了兩種對(duì)象。
* 這里創(chuàng)建兩種對(duì)象的原因是為了 后面創(chuàng)建的線程互相持有鎖。
*/
for (int i = 0; i < createThreadNum; i++) {
if (i % 2 != 0) {
// i 為 奇數(shù)時(shí),給 DeadLockObj 對(duì)象的 a = 1,b = 2。
deadLockObjList.add(new DeadLockObj(i, 1, 2));
} else {
// i 為 偶數(shù)時(shí),給 DeadLockObj 對(duì)象的 a = 2,b = 1。
deadLockObjList.add(new DeadLockObj(i, 2, 1));
}
}
deadLockObjList.sort(Comparator.comparingInt(DeadLockObj::getId));
// 循環(huán)數(shù)據(jù),調(diào)用 deadLockInternal()方法,展示死鎖情況。
deadLockObjList.forEach(deadLockObj -> {
this.threadPoolTaskExecutor.execute(() -> {
try {
sunCdl.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 在高并發(fā)情況下,必然會(huì)出現(xiàn)死鎖。
this.deadLockInternal(deadLockObj);
});
});
// 循環(huán)將 計(jì)數(shù)器 減1,當(dāng)減為0時(shí),上面的線程就開始 真正的并發(fā)執(zhí)行。
for (int i = 0; i < createThreadNum; i++) {
sunCdl.countDown();
}
}
private void deadLockInternal(DeadLockObj deadLockObj) {
/**
* ① 線程A 持有 Integer.valueOf(1),線程B 持有 Integer.valueOf(2)
* ② 線程A 搶占 Integer.valueOf(2),但是2被線程B持有。
* 同時(shí),線程B 搶占 Integer.valueOf(1),但是1被線程A持有。
* 線程A 和 線程B 要搶占的鎖都被對(duì)方持有,所以,必然會(huì)出現(xiàn)死鎖。
*/
// 第一把鎖
synchronized (Integer.valueOf(deadLockObj.getA())) {
// 第二把鎖
synchronized (Integer.valueOf(deadLockObj.getB())) {
System.out.println(deadLockObj.getId());
}
}
}
@Getter
@AllArgsConstructor
static class DeadLockObj {
Integer id;
int a;
int b;
}
}2. 死鎖線程查看
2.1 第一步
當(dāng) java程序發(fā)生死鎖時(shí),JavaVisualVM 的 "線程"標(biāo)簽頁 會(huì)自動(dòng)顯示紅色提示信息:“檢測(cè)到死鎖!生成一個(gè)線程dump以獲取更多信息”。如下圖所示:

JavaVisualVM 不能很方便的查看到到底是哪幾個(gè)線程發(fā)生了死鎖,所以,接下來我們就可以用到 JConsole了。
【備注】:JavaVisualVM 在JDK8的時(shí)候還是自帶工具,到JDK11的時(shí)候就不是自帶的了,但還是可以免費(fèi)下載和免費(fèi)試用的。(至于JDK9、10有沒有自帶不知道,沒下載過)。
2.2 第二步
上面一步,JavaVisualVM 已經(jīng)【自動(dòng)】給我們提示出現(xiàn)了【死鎖】。這里,我們就可以用 JConsole 來查看了。

死鎖 小標(biāo)簽頁,我們隨便點(diǎn)擊一個(gè)線程就可以查看對(duì)應(yīng)的 線程快照信息。

到此這篇關(guān)于Java線程死鎖的問題解決的文章就介紹到這了,更多相關(guān)Java線程死鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot的application.yml不生效問題及解決
這篇文章主要介紹了SpringBoot的application.yml不生效問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
Java實(shí)現(xiàn)獲取小程序帶參二維碼并保存到本地
這篇文章主要介紹了Java實(shí)現(xiàn)獲取小程序帶參二維碼并保存到本地,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Java吃貨聯(lián)盟訂餐系統(tǒng)代碼實(shí)例
這篇文章主要介紹了Java訂餐系統(tǒng),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Java數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之循環(huán)鏈表
循環(huán)鏈表是另一種形式的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)。它的特點(diǎn)是表中最后一個(gè)結(jié)點(diǎn)的指針域指向頭結(jié)點(diǎn),整個(gè)鏈表形成一個(gè)環(huán)。本文將為大家詳細(xì)介紹一下循環(huán)鏈表的特點(diǎn)與使用,需要的可以了解一下2021-12-12
Spring Boot 2.7.8 原生 SSE 服務(wù)端開發(fā)實(shí)戰(zhàn)指南
在Spring Boot 2.7.8版本中,我們可以利用其原生支持,輕松實(shí)現(xiàn)SSE服務(wù),從而為應(yīng)用提供實(shí)時(shí)數(shù)據(jù)推送能力,本文給大家介紹Spring Boot 2.7.8 原生 SSE 服務(wù)端開發(fā)實(shí)戰(zhàn)指南,感興趣的朋友一起看看吧2026-04-04
maven報(bào)錯(cuò):Failed to execute goal on p
這篇文章主要介紹了maven報(bào)錯(cuò):Failed to execute goal on project問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
Java多線程讀寫鎖ReentrantReadWriteLock類詳解
本文詳細(xì)講解了Java多線程讀寫鎖ReentrantReadWriteLock類,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
從基礎(chǔ)實(shí)現(xiàn)到性能優(yōu)化詳解Java實(shí)現(xiàn)Word轉(zhuǎn)HTML的完整指南
本文將基于實(shí)際項(xiàng)目經(jīng)驗(yàn),介紹 Java 中 Word 轉(zhuǎn) HTML 的幾種實(shí)現(xiàn)方案,并以其中一種為例詳細(xì)講解轉(zhuǎn)換過程中的關(guān)鍵配置,性能優(yōu)化及常見問題處理2026-04-04
Servlet實(shí)現(xiàn)點(diǎn)擊計(jì)數(shù)器的方法
這篇文章主要介紹了Servlet實(shí)現(xiàn)點(diǎn)擊計(jì)數(shù)器的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08

