一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Java死鎖的原因例子及解決方法

 忠波irlphwt1ng 2020-02-24

Java發(fā)生死鎖的根本原因是:在申請鎖時發(fā)生了交叉閉環(huán)申請。即線程在獲得了鎖A并且沒有釋放的情況下去申請鎖B,這時,另一個線程已經(jīng)獲得了鎖B,在釋放鎖B之前又要先獲得鎖A,因此閉環(huán)發(fā)生,陷入死鎖循環(huán)。

死鎖發(fā)生的例子1:

public class DeadLockA extends Thread {
    @Override
    public void run() {
        try{
            System.out.println("LockA running");
            while(true){
                synchronized(Client.obj1){
                    System.out.println("LockA locked obj1");
                    //獲取obj1后先等一會兒,讓LockB有足夠的時間鎖住obj2
                    Thread.sleep(100);
                    System.out.println("LockA trying to lock obj2...");
                    synchronized(Client.obj2){
                        System.out.println("LockA locked obj2");
                    }
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
public class DeadLockB extends Thread {
    @Override
    public void run() {
        try{
            System.out.println("LockB running");
            while(true){
                synchronized(Client.obj2){
                    System.out.println("LockB locked obj2");
                    System.out.println("LockB trying to lock obj1...");
                    synchronized(Client.obj1){
                        System.out.println("LockB locked obj1");
                    }
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
public class Client {
    public static final String obj1 = "obj1";
    public static final String obj2 = "obj2";

    public static void main(String[] ars) {
        new DeadLockA().start();
        new DeadLockB().start();
    }
}

運行結果:
這里寫圖片描述
結果顯示兩個線程最后都在等待對方釋放鎖,最終進入了死鎖狀態(tài)。

死鎖發(fā)生的例子2:

public class TestClass {

    public synchronized void method(TestClass clazz) {
        System.out.println("TestClass method in");
        clazz.method2();
        System.out.println("TestClass method out");
    }

    public synchronized void method2() {
        System.out.println("TestClass method2");
    }
}
public class TestLock extends Thread {
    private TestClass class1;
    private TestClass class2;

    public TestLock(TestClass class1, TestClass class2) {
        this.class1 = class1;
        this.class2 = class2;
    }

    @Override
    public void run() {
        class1.method(class2);
    }
}
public class Client {
    public static void main(String[] ars) {
        TestClass classA = new TestClass();
        TestClass classB = new TestClass();
        new TestLock(classA, classB).start();
        new TestLock(classB, classA).start();
    }
}

運行結果:
這里寫圖片描述
結果顯示進入兩次方法,但是并沒有走完,發(fā)生死鎖。

一旦出現(xiàn)死鎖,整個程序既不會發(fā)生任何錯誤,也不會給出任何提示,只是所有線程處于阻塞狀態(tài),無法繼續(xù)。java虛擬機沒有提供檢測,也沒有采取任何措施來處理死鎖的情況,所以多線程編程中,必須手動應該采取措施避免死鎖。

解決方法:

1.調(diào)整申請鎖的范圍

public class TestClass {

    public void method(TestClass clazz) {
        System.out.println("TestClass method in");
        synchronized(this){
            //do something
        }
        clazz.method2();
        System.out.println("TestClass method out");
    }

    public synchronized void method2() {
        System.out.println("TestClass method2");
    }
}

上面代碼原來鎖是加在方法上的,現(xiàn)在改為在方法內(nèi)的一部分,這樣在使用第二個鎖時本身的鎖已經(jīng)釋放了。如果減小鎖的申請范圍可以避免鎖的申請發(fā)生閉環(huán)的話,那么就可以避免死鎖。

2.調(diào)整申請鎖的順序

在有些情況下是不允許我們調(diào)整鎖的范圍的,比如銀行轉賬的場景下,我們必須同時獲得兩個賬戶上的鎖,才能進行操作,兩個鎖的申請必須發(fā)生交叉。這時要想打破死鎖閉環(huán),必須調(diào)整鎖的申請順序,總是以相同的順序來申請鎖,比如總是先申請 id 大的賬戶上的鎖 ,然后再申請 id 小的賬戶上的鎖,這樣就無法形成導致死鎖的那個閉環(huán)。

public class Account {
    private int id;    // 主鍵
    private String name;
    private double balance;

    public void transfer(Account from, Account to, double money){
        if(from.getId() > to.getId()){
            synchronized(from){
                synchronized(to){
                    // transfer
                }
            }
        }else{
            synchronized(to){
                synchronized(from){
                    // transfer
                }
            }
        }
    }

    public int getId() {
        return id;
    }
}

這樣的話,即使發(fā)生了兩個賬戶比如 id=1的和id=100的兩個賬戶相互轉賬,因為不管是哪個線程先獲得了id=100上的鎖,另外一個線程都不會去獲得id=1上的鎖(因為他沒有獲得id=100上的鎖),只能是哪個線程先獲得id=100上的鎖,哪個線程就先進行轉賬。這里除了使用id之外,如果沒有類似id這樣的屬性可以比較,那么也可以使用對象的hashCode()的值來進行比較。

避免死鎖的發(fā)生

很多時候?qū)嶋H鎖的交叉可能涉及很多個,要想很好的避免只能人工仔細檢查,一旦我們在一個同步方法中,或者說在一個鎖的保護的范圍中,調(diào)用了其它對象的方法時,就要十分的小心:

1. 如果其它對象的這個方法會消耗比較長的時間,那么就會導致鎖被我們持有了很長的時間;
2. 如果其它對象的這個方法是一個同步方法,那么就要注意避免發(fā)生死鎖的可能性了;

總之是盡量避免在一個同步方法中調(diào)用其它對象的延時方法和同步方法。

參考:
https://blog.csdn.net/xidianliuy/article/details/51568073
https://blog.csdn.net/m0_38126177/article/details/78587845

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    欧美日韩综合在线精品| 午夜精品国产一区在线观看| 国产成人亚洲综合色就色| 国产欧美日韩不卡在线视频| 成年女人午夜在线视频| 欧美午夜不卡在线观看| 欧美日韩亚洲国产av| 男女一进一出午夜视频| 国内九一激情白浆发布| 日韩精品人妻少妇一区二区| 欧美丰满大屁股一区二区三区| 办公室丝袜高跟秘书国产| 国产一级内片内射免费看| 青青操视频在线播放免费| 欧美欧美日韩综合一区| 91久久精品国产成人| 国产精品一区二区三区欧美 | 丰满熟女少妇一区二区三区| 亚洲精品福利视频在线观看| 97人妻人人揉人人躁人人| 国产亚洲欧美自拍中文自拍| 亚洲清纯一区二区三区| 亚洲做性视频在线播放| 深夜视频成人在线观看| 日本道播放一区二区三区| 九九热这里只有精品视频| 99精品国产自在现线观看| 人妻久久一区二区三区精品99| 亚洲欧美日本成人在线| 国产又粗又猛又长又黄视频| 日本精品啪啪一区二区三区| 亚洲视频在线观看你懂的| 婷婷激情五月天丁香社区| 国产熟女一区二区三区四区| 成年人黄片大全在线观看| 欧美精品在线观看国产| 婷婷激情四射在线观看视频| 青草草在线视频免费视频| 日韩日韩欧美国产精品| 欧美午夜国产在线观看| 日韩一级欧美一级久久|

    AI助手

    阅读时有疑惑?点击向AI助手提问吧

    联系客服

    微信扫码,添加客服企业微信

    客服QQ:

    1732698931

    联系电话:4000-999-276

    客服工作时间9:00-18:00,晚上非工作时间,请在微信或QQ留言,第二天客服上班后会立即联系您。