最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何解決Java多線程死鎖問題

 更新時(shí)間:2021年05月13日 09:32:23   作者:Putarmor  
死鎖是一個(gè)很嚴(yán)重的、必須要引起重視的問題,本文主要介紹了死鎖的定義,解決方法和面試會(huì)遇到的問題,感興趣的可以了解一下

死鎖問題

死鎖定義

多線程編程中,因?yàn)閾屨假Y源造成了線程無限等待的情況,此情況稱為死鎖。

死鎖舉例

注意:線程和鎖的關(guān)系是:一個(gè)線程可以擁有多把鎖,一個(gè)鎖只能被一個(gè)線程擁有。

當(dāng)兩個(gè)線程分別擁有一把各自的鎖之后,又嘗試去獲取對(duì)方的鎖,這樣就會(huì)導(dǎo)致死鎖情況的發(fā)生,具體先看下面代碼:

/**
 * 線程死鎖問題
 */
public class DeadLock {
    public static void main(String[] args) {
        //創(chuàng)建兩個(gè)鎖對(duì)象
        Object lock1 = new Object();
        Object lock2 = new Object();

        //創(chuàng)建子線程
        /*
        線程1:①先獲得鎖1 ②休眠1s,讓線程2獲得鎖2 ③線程1嘗試獲取鎖2 線程2同理
         */
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //線程1業(yè)務(wù)邏輯
                synchronized(lock1){
                    System.out.println("線程1得到了鎖子1");
                    try {
                        //休眠1s,讓線程2先得到鎖2
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程1嘗試獲取鎖2...");
                    synchronized(lock2){
                        System.out.println("線程1獲得了鎖2!");
                    }
                }
            }
        },"線程1");


        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //線程2業(yè)務(wù)邏輯
                synchronized(lock2){
                    System.out.println("線程2得到了鎖子2");
                    try {
                //休眠1s,讓線程1先得到鎖1;因?yàn)榫€程是并發(fā)執(zhí)行我們不知道誰先執(zhí)行
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程2嘗試獲取鎖1...");
                    synchronized(lock1){
                        System.out.println("線程2獲得了鎖1");
                    }
                }
            }
        },"線程2");
        thread1.start();
        thread2.start();
    }
}

程序運(yùn)行結(jié)果如下:

在這里插入圖片描述 

可以看出,線程1嘗試獲取了鎖2,線程2嘗試獲取了鎖1,但是二者并沒有獲取到對(duì)方的鎖;這就發(fā)生了所謂的“死鎖”!

如何排查死鎖

想要排查死鎖具體細(xì)節(jié),可以通過三個(gè)工具(位于jdk安裝路徑bin目錄)去排查,現(xiàn)在就給大家介紹一下:

1.jconsole

在這里插入圖片描述

可以看出,線程1和線程2發(fā)生了死鎖,死鎖發(fā)生的位置一目了然

2.jvisualvm

在這里插入圖片描述

可以看出,發(fā)生了死鎖,線程1和線程2嘗試獲取的鎖是對(duì)方的鎖。

3.jmc

在這里插入圖片描述

可以看出,同樣檢測出了死鎖情況
無論是用哪個(gè)工具排查死鎖情況都是OK的。

死鎖發(fā)生的條件

1.互斥條件(一個(gè)鎖只能被一個(gè)線程占有,當(dāng)一個(gè)鎖被一個(gè)線程持有之后,不能再被其他線程持有);
2.請(qǐng)求擁有(一個(gè)線程擁有一把鎖之后,又去嘗試請(qǐng)求擁有另外一把鎖);可以解決
3.不可剝奪(一個(gè)鎖被一個(gè)線程占有之后,如果該線程沒有釋放鎖,其他線程不能強(qiáng)制獲得該鎖);
4.環(huán)路等待條件(多線程獲取鎖時(shí)形成了一個(gè)環(huán)形鏈)可以解決

怎么解決死鎖問題?

環(huán)路等待條件相對(duì)于請(qǐng)求擁有更容易實(shí)現(xiàn),那么通過破壞環(huán)路等待條件解決死鎖問題
破壞環(huán)路等待條件示意圖:

在這里插入圖片描述

針對(duì)于上面死鎖舉例中代碼,解決死鎖,具體看下面代碼:

/**
 * 線程死鎖問題
 */
public class DeadLock {
    public static void main(String[] args) {
        //創(chuàng)建兩個(gè)鎖對(duì)象
        Object lock1 = new Object();
        Object lock2 = new Object();

        //創(chuàng)建子線程
        /*
        線程1:①先獲得鎖1 ②休眠1s,讓線程2獲得鎖2 ③線程1嘗試獲取鎖2 線程2同理
         */
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //線程1業(yè)務(wù)邏輯
                synchronized(lock1){
                    System.out.println("線程1得到了鎖子1");
                    try {
                        //休眠1s,讓線程2先得到鎖2
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程1嘗試獲取鎖2...");
                    synchronized(lock2){
                        System.out.println("線程1獲得了鎖2!");
                    }
                }
            }
        },"線程1");


        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //線程2業(yè)務(wù)邏輯
                synchronized(lock2){
                    System.out.println("線程2得到了鎖子2");
                    try {
                //休眠1s,讓線程1先得到鎖1;因?yàn)榫€程是并發(fā)執(zhí)行我們不知道誰先執(zhí)行
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程2嘗試獲取鎖1...");
                    synchronized(lock1){
                        System.out.println("線程2獲得了鎖1");
                    }
                }
            }
        },"線程2");
        thread1.start();
        thread2.start();
    }
}

程序運(yùn)行結(jié)果如下:

在這里插入圖片描述

可以看出,通過破壞環(huán)路等待條件完美解決了死鎖問題

線程通訊機(jī)制(wait/notify/notifyAll)

定義

線程通訊機(jī)制:一個(gè)線程的動(dòng)作可以讓另外一個(gè)線程感知到,這就是線程通訊機(jī)制。
wait():讓當(dāng)前線程進(jìn)入休眠等待狀態(tài);
notify():喚醒當(dāng)前對(duì)象上的休眠等待線程;
notifyAll():喚醒當(dāng)前對(duì)象上的所有休眠等待線程。

相關(guān)面試重點(diǎn)

面試問題:
1.wait()使用時(shí)為什么需要加鎖?
因?yàn)閣ait()必須在同步方法或者同步塊中使用,也就是說wait()需要配合加鎖一起使用(比如synchronized或Lock),調(diào)用對(duì)象調(diào)用wait()如果沒有適當(dāng)?shù)逆i,就會(huì)引發(fā)異常,因此說wait()使用時(shí)需要加鎖。
2.wait()使用為什么要釋放鎖?
wait()是Objetc類中一個(gè)實(shí)例方法,默認(rèn)是不傳任何值的,不傳值的時(shí)候表示讓當(dāng)前線程處于永久休眠等待狀態(tài),這樣會(huì)造成一個(gè)鎖被一個(gè)線程長時(shí)間一直擁有,為了避免這種問題的發(fā)生,使用wait()后必須釋放鎖。

wait()/notify()/notifyAll()使用時(shí)注意事項(xiàng):
使用這三個(gè)方法時(shí)都必須進(jìn)行加鎖;
2.加鎖的對(duì)象和調(diào)用wait()/notify()/notifyAll()對(duì)象必須是同一個(gè)對(duì)象;
3.一組wait()/notify()/notifyAll()必須是同一個(gè)對(duì)象;
4.notify()只能喚醒當(dāng)前對(duì)象上的一個(gè)休眠等到線程;而notifyAll()可以喚醒當(dāng)前對(duì)象上的所有休眠等待線程。

sleep(0)和wait(0)的區(qū)別:
1.sleep()是Thread類中一個(gè)靜態(tài)方法,wait()是Object類中一個(gè)普通的成員方法;
2.sleep(0)會(huì)立即觸發(fā)一次CPU的搶占執(zhí)行,wait(0)會(huì)讓當(dāng)前線程無限休眠等待下去。

wait()和sleep()的區(qū)別:
相同點(diǎn):
1.都會(huì)讓當(dāng)前線程進(jìn)行休眠等待;
2.使用二者時(shí)都需處理InterruptedException異常(try/catch)。
不同點(diǎn):
1.wait()是Object中普通成員方法,sleep是Thread中靜態(tài)方法;
2.wait()使用可以不穿參數(shù),sleep()必須傳入一個(gè)大于等于0的參數(shù);
3.wait()使用時(shí)必須配合加鎖一起使用,sleep()使用時(shí)不需要加鎖;
4.wait()使用時(shí)需要釋放鎖,如果sleep()加鎖后不會(huì)釋放鎖;
5.wait()會(huì)讓當(dāng)前線程進(jìn)入WAITING狀態(tài)(默認(rèn)沒有明確的等待時(shí)間,當(dāng)被別的線程喚醒或者wait()傳參后超過等待時(shí)間量自己喚醒,將進(jìn)入就緒狀態(tài)),sleep()會(huì)讓當(dāng)前線程進(jìn)入TIMED_WAITING狀態(tài)(有明確的結(jié)束等待時(shí)間,但是這是死等的方式,休眠結(jié)束后進(jìn)入就緒狀態(tài))。

*為什么wait()處于Object中而不是Thread中?(有點(diǎn)繞 我有點(diǎn)懵了…)
wait()的調(diào)用必須進(jìn)行加鎖和釋放鎖操作,而鎖是屬于對(duì)象級(jí)別非線程級(jí)別,也就是說鎖針對(duì)于對(duì)象進(jìn)行操作而不是線程;而線程和鎖是一對(duì)多的關(guān)系,一個(gè)線程可以擁有多把鎖,而一個(gè)線程只能被一個(gè)線程擁有,為了靈活操作,就將wait()放在Object中。

LockSupport

LockSupport是對(duì)wait()的升級(jí),無需加鎖也無需釋放鎖;

LockSupport.park()讓線程休眠,和wait()一樣會(huì)讓線程進(jìn)入WAITING狀態(tài);LockSupport.unpark()喚醒線程,可以喚醒對(duì)象上指定的休眠等待線程;(優(yōu)勢)

LockSupport與wait()區(qū)別

wait()與LockSupport的區(qū)別:

相同點(diǎn):
1.二者都可以讓線程進(jìn)入休眠等待狀態(tài);
2.二者都可以傳參或者不傳參,讓線程都會(huì)進(jìn)入到WAITING狀態(tài)。
不同點(diǎn):
1.wait()需要配合加鎖一起使用,LockSupport無需加鎖;
2.wait()只能喚醒對(duì)象的隨機(jī)休眠線程和全部線程,LockSupport可以喚醒對(duì)象的指定休眠線程。

到此這篇關(guān)于如何解決Java多線程死鎖問題的文章就介紹到這了,更多相關(guān)Java多線程死鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 三分鐘快速掌握J(rèn)ava中枚舉(enum)

    三分鐘快速掌握J(rèn)ava中枚舉(enum)

    enum的全稱為enumeration, 是 JDK 1.5中引入的新特性,存放在 java.lang包中。下面這篇文章是我在使用enum過程中的一些經(jīng)驗(yàn)和總結(jié),分享出來方便大家快速的掌握J(rèn)ava中枚舉(enum),有需要的朋友們下面跟著小編來一起看看吧。
    2016-12-12
  • Java并發(fā)編程示例(八):處理線程的非受檢異常

    Java并發(fā)編程示例(八):處理線程的非受檢異常

    這篇文章主要介紹了Java并發(fā)編程示例(八):處理線程的非受檢異常,Java為我們提供了一種機(jī)制,專門用于處理由Thread對(duì)象拋出的非受檢異常,以避免程序的退出,需要的朋友可以參考下
    2014-12-12
  • Springboot-dubbo-fescar 阿里分布式事務(wù)的實(shí)現(xiàn)方法

    Springboot-dubbo-fescar 阿里分布式事務(wù)的實(shí)現(xiàn)方法

    這篇文章主要介紹了Springboot-dubbo-fescar 阿里分布式事務(wù)的實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-03-03
  • 最安全的加密算法Bcrypt防止數(shù)據(jù)泄露詳解

    最安全的加密算法Bcrypt防止數(shù)據(jù)泄露詳解

    這篇文章主要為大家介紹了最安全的加密算法Bcrypt防止數(shù)據(jù)泄露詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 理解 MyBatis 是如何在 Spring 容器中初始化的

    理解 MyBatis 是如何在 Spring 容器中初始化的

    這篇文章主要介紹了理解 MyBatis 是如何在 Spring 容器中初始化的,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • SpringBoot3.x版本與Mybatis-Plus不兼容問題

    SpringBoot3.x版本與Mybatis-Plus不兼容問題

    當(dāng)使用3.x版本的SpringBoot結(jié)合Mybatis-Plus時(shí)版本不兼容就會(huì)報(bào)錯(cuò),本文就來介紹一下這個(gè)問題的解決方法,感興趣的可以了解一下
    2024-03-03
  • 淺談hibernate之映射文件VS映射注解

    淺談hibernate之映射文件VS映射注解

    下面小編就為大家?guī)硪黄獪\談hibernate之映射文件VS映射注解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • Java 實(shí)戰(zhàn)范例之線上新聞平臺(tái)系統(tǒng)的實(shí)現(xiàn)

    Java 實(shí)戰(zhàn)范例之線上新聞平臺(tái)系統(tǒng)的實(shí)現(xiàn)

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+jsp+jdbc+mysql實(shí)現(xiàn)一個(gè)線上新聞平臺(tái)系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • java中thread線程start和run的區(qū)別

    java中thread線程start和run的區(qū)別

    這篇文章主要介紹了java中thread線程start和run的區(qū)別,run()是Runnable接口中定義的一個(gè)方法,是為了讓客戶程序員在這個(gè)方法里寫自己的功能代碼的。直接調(diào)用和普通的類調(diào)用自己的成員方法是沒有任何區(qū)別的
    2014-03-03
  • IDEA中的maven沒有dependencies解決方案

    IDEA中的maven沒有dependencies解決方案

    這篇文章主要介紹了IDEA中的maven沒有dependencies解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05

最新評(píng)論

四川省| 韶关市| 潍坊市| 北安市| 南宁市| 宜城市| 黔江区| 宁都县| 蓬莱市| 怀安县| 玉龙| 麻栗坡县| 三都| 同仁县| 北川| 桃园县| 桂东县| 望谟县| 本溪市| 湖北省| 象山县| 内江市| 梁平县| 石景山区| 娱乐| 新民市| 新建县| 天门市| SHOW| 东山县| 阿巴嘎旗| 吉安县| 卢氏县| 苍南县| 昆山市| 衡水市| 五河县| 通渭县| 凉城县| 云龙县| 尉氏县|