欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

死鎖問題

死鎖定義

多線程編程中,因為搶占資源造成了線程無限等待的情況,此情況稱為死鎖。

死鎖舉例

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

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

/**
 * 線程死鎖問題
 */
public class DeadLock {
    public static void main(String[] args) {
        //創(chuàng)建兩個鎖對象
        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;因為線程是并發(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();
    }
}

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

在這里插入圖片描述 

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

如何排查死鎖

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

1.jconsole

在這里插入圖片描述

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

2.jvisualvm

在這里插入圖片描述

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

3.jmc

在這里插入圖片描述

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

死鎖發(fā)生的條件

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

怎么解決死鎖問題?

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

在這里插入圖片描述

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

/**
 * 線程死鎖問題
 */
public class DeadLock {
    public static void main(String[] args) {
        //創(chuàng)建兩個鎖對象
        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;因為線程是并發(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();
    }
}

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

在這里插入圖片描述

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

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

定義

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

相關(guān)面試重點

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

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

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

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

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

LockSupport

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

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

LockSupport與wait()區(qū)別

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

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

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

相關(guān)文章

  • java 接口回調(diào)實例詳解

    java 接口回調(diào)實例詳解

    這篇文章主要介紹了java 接口回調(diào)實例詳解的相關(guān)資料,所謂回調(diào)就是使用java中的多態(tài),需要的朋友可以參考下
    2017-07-07
  • SpringBoot為何可以使用Jar包啟動詳解

    SpringBoot為何可以使用Jar包啟動詳解

    springboot jar包啟動腳本,適用于快速啟動,刪除,重啟,以及查看狀態(tài),下面這篇文章主要給大家介紹了關(guān)于SpringBoot為何可以使用Jar包啟動的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • 在Spring中實現(xiàn)異步處理的步驟和代碼演示

    在Spring中實現(xiàn)異步處理的步驟和代碼演示

    在Spring中實現(xiàn)異步處理通常涉及到@Async注解,通過步驟和代碼演示,可以在Spring應用程序中實現(xiàn)異步處理,記住要根據(jù)你的應用程序的實際需求來調(diào)整線程池和異步方法的設(shè)計,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • 常用Eclipse快捷方式(推薦)

    常用Eclipse快捷方式(推薦)

    下面小編就為大家?guī)硪黄S肊clipse快捷方式(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • 兩張動圖--帶你搞懂TCP的三次握手與四次揮手

    兩張動圖--帶你搞懂TCP的三次握手與四次揮手

    TCP是一種傳輸控制協(xié)議,是面向連接的、可靠的、基于字節(jié)流之間的傳輸層通信協(xié)議,由IETF的RFC 793定義。在簡化的計算機網(wǎng)絡(luò)OSI模型中,TCP完成第四層傳輸層所指定的功能
    2021-06-06
  • 淺談java 中文件的讀取File、以及相對路徑的問題

    淺談java 中文件的讀取File、以及相對路徑的問題

    今天小編就為大家分享一篇淺談java 中文件的讀取File、以及相對路徑的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • Java 類加載機制詳細介紹

    Java 類加載機制詳細介紹

    這篇文章主要介紹了Java 類加載機制詳細介紹的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Java實現(xiàn)微信公眾平臺朋友圈分享功能詳細代碼

    Java實現(xiàn)微信公眾平臺朋友圈分享功能詳細代碼

    這篇文章主要介紹了Java實現(xiàn)微信公眾平臺朋友圈分享功能詳細代碼,小編覺得挺不錯的,這里分享給大家,供需要的朋友參考。
    2017-11-11
  • IDEA插件之Mybatis Log plugin 破解及安裝方法

    IDEA插件之Mybatis Log plugin 破解及安裝方法

    這篇文章主要介紹了IDEA插件之Mybatis Log plugin 破解方法及安裝方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • intellij idea 2021.2 打包并上傳運行spring boot項目的詳細過程(spring boot 2.5.4)

    intellij idea 2021.2 打包并上傳運行spring boot項目的詳細過程(spring boot 2

    這篇文章主要介紹了intellij idea 2021.2 打包并上傳運行一個spring boot項目(spring boot 2.5.4),本文通過圖文并茂的形式給大家介紹的非常詳細,需要的朋友可以參考下
    2021-09-09

最新評論