Java多線程之死鎖詳解
1、死鎖
出現(xiàn)場(chǎng)景:當(dāng)線程A擁有了A對(duì)象的鎖,想要去獲取B對(duì)象的鎖;線程B擁有了B對(duì)象的鎖,想要擁有A對(duì)象的鎖,兩個(gè)線程在獲取鎖的時(shí)候,都不會(huì)釋放已經(jīng)持有的鎖,于是,就造成了死鎖。
示例代碼:
@Slf4j
public class ThreadTest {
private static Object objectA = new Object();
private static Object objectB = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t2 = new Thread(()->{
synchronized (objectA){
log.debug("線程t2獲取到了objectA");
synchronized (objectB){
log.debug("線程t2獲取到了objectB");
}
}
},"t2");
Thread t1 = new Thread(()->{
synchronized (objectB){
log.debug("線程t1獲取到了objectB");
synchronized (objectA){
log.debug("線程t1獲取到了objectA");
}
}
},"t1");
t2.start();
t1.start();
}
}
如何檢測(cè)死鎖:
兩種方法
(1)找到本機(jī)jconsole程序,直接在windows系統(tǒng)搜索就可以,打開是這個(gè)樣子。

然后在本地進(jìn)程里面選擇你的進(jìn)程,其實(shí)就是你的項(xiàng)目名稱。然后點(diǎn)擊連接,在點(diǎn)擊不安全連接。

進(jìn)去之后點(diǎn)擊線程

再點(diǎn)擊檢測(cè)死鎖

最后就能看到死鎖的線程了

(2)首先是在idea的控制臺(tái),打開Terminal,輸入【jps】命令查看所有的進(jìn)程id,找到你自己的java類名稱對(duì)應(yīng)的id。
然后輸入【jstack + 進(jìn)程號(hào)】 就可以查詢到該進(jìn)程的所有線程信息。在輸出信息的最下面,就可以看到如下圖所示的線程死鎖信息。

2、死鎖經(jīng)典問題——哲學(xué)家就餐問題
經(jīng)典場(chǎng)景:有四位哲學(xué)及在一正方形的桌子上面吃飯,桌子的每個(gè)角有一根筷子,一共四根,那么,當(dāng)每個(gè)哲學(xué)家都拿起自己左邊的筷子之后,再去拿自己右邊的筷子的時(shí)候,就會(huì)發(fā)現(xiàn)自己右邊沒有筷子,這時(shí)哲學(xué)就就會(huì)等右邊的哲學(xué)家放下筷子,但是每個(gè)哲學(xué)家都是這個(gè)想法,那么都不會(huì)放下筷子,并且都拿不到右邊的筷子,因此就造成了死鎖。
代碼實(shí)現(xiàn)例子:
@Slf4j
public class Thread1 {
public static void main(String[] args) throws InterruptedException {
//筷子對(duì)象
Chopsticks c1 = new Chopsticks("c1");
Chopsticks c2 = new Chopsticks("c2");
Chopsticks c3 = new Chopsticks("c3");
Chopsticks c4 = new Chopsticks("c4");
new Philosopher("李云龍",c1,c2).start();
new Philosopher("趙剛",c2,c3).start();
new Philosopher("魏和尚",c3,c4).start();
new Philosopher("張大彪",c4,c1).start();
}
}
//筷子
class Chopsticks{
private String name;
public Chopsticks(String name) {
this.name = name;
}
}
//哲學(xué)家
@Slf4j
class Philosopher extends Thread{
//名字
private String name;
//筷子
private Chopsticks left;
private Chopsticks right;
public Philosopher(String name, Chopsticks left, Chopsticks right) {
super(name);
this.left = left;
this.right = right;
}
@Override
public void run() {
while(true){
synchronized (right){
synchronized (left){
eat(name);
}
}
}
}
private void eat(String name){
log.debug(name + "正在吃飯");
}
}
測(cè)試結(jié)果:可以實(shí)現(xiàn)吃飯操作,但是會(huì)出現(xiàn)場(chǎng)景中描述的問題,出現(xiàn)線程死鎖。

總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java使用正則表達(dá)式判斷獨(dú)立字符的存在(代碼示例)
通過使用正則表達(dá)式,我們可以更加靈活地判斷字符串中是否包含特定的字符,并且可以控制匹配的條件,如獨(dú)立的字符,這為我們處理字符串提供了更多的選擇和功能,這篇文章主要介紹了Java使用正則表達(dá)式判斷獨(dú)立字符的存在,需要的朋友可以參考下2023-10-10
SpringBoot整合Quartz實(shí)現(xiàn)定時(shí)任務(wù)詳解
這篇文章主要介紹了Java?任務(wù)調(diào)度框架?Quartz,Quartz是OpenSymphony開源組織在Job?scheduling領(lǐng)域又一個(gè)開源項(xiàng)目,完全由Java開發(fā),可以用來執(zhí)行定時(shí)任務(wù),類似于java.util.Timer。,下面我們來學(xué)習(xí)一下關(guān)于?Quartz更多的詳細(xì)內(nèi)容,需要的朋友可以參考一下2022-08-08
Spring Boot數(shù)據(jù)庫鏈接池配置方法
這篇文章主要介紹了Spring Boot數(shù)據(jù)庫鏈接池配置方法,需要的朋友可以參考下2017-04-04
利用HttpUrlConnection 上傳 接收文件的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄肏ttpUrlConnection 上傳 接收文件的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11
利用Java如何實(shí)現(xiàn)將二維數(shù)組轉(zhuǎn)化為鏈?zhǔn)絻?chǔ)存
鏈?zhǔn)浇Y(jié)構(gòu)不要求邏輯上相鄰的節(jié)點(diǎn)在物理位置上也相鄰,節(jié)點(diǎn)間的邏輯關(guān)系是由附加的指針字段表示的,通常借助于程序設(shè)計(jì)中的指針結(jié)構(gòu)來實(shí)現(xiàn),這篇文章主要給大家介紹了關(guān)于利用Java如何實(shí)現(xiàn)將二維數(shù)組轉(zhuǎn)化為鏈?zhǔn)絻?chǔ)存的相關(guān)資料,需要的朋友可以參考下2021-12-12

