日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

在并發(fā)環(huán)境中,我們?yōu)榱吮WC共享可變數(shù)據(jù)的線程安全性,需要使用加鎖機制,如果鎖使用不當可能會引起死鎖,線程饑餓等問題。

在JAVA應(yīng)用程序中如果發(fā)生死鎖,程序是無法自動恢復的,嚴重會造成程序崩潰,所以開發(fā)中在設(shè)計階段就要規(guī)避死鎖發(fā)生的情況。

 

什么是死鎖

 

死鎖:每個線程擁有其他線程需要的資源,同時又等待其他線程擁有的資源,并且每個線程在獲得所需要的資源前都不會放棄已經(jīng)擁有的資源。

程序死鎖發(fā)生的場景:

1)交叉鎖導致死鎖

在線程A持有鎖L并想獲取鎖R的同時,線程B持有鎖R并嘗試獲得鎖L,那么這兩個線程將永遠的阻塞下去。交叉鎖的發(fā)生一般是因為線程以不同的順序獲取鎖。

2)資源死鎖

內(nèi)存不足或者我們在程序中使用了線程池和信號量對資源進行限制時,兩個線程互相等待彼此釋放資源而進入永久阻塞。

3)死循環(huán)死鎖

程序由于代碼缺陷或者重試機制而使代碼陷入死循環(huán),造成了內(nèi)存和cpu的大量消耗而使線程進入阻塞。

當Java程序發(fā)生死鎖時,阻塞的線程將永遠不能使用了,而且可能造成程序停止或者使CPU飆高使程序性能很差。恢復程序的唯一方式就是重啟應(yīng)用。

死鎖的發(fā)生大多數(shù)是偶然情況,并不代表一個類發(fā)生死鎖,它就一直死鎖,這也是死鎖難以排查的原因。

通過死鎖發(fā)生的場景我們可以總結(jié)出死鎖發(fā)生的條件:

  • 互斥:即鎖具有排他性,只有一個線程能夠獲取鎖;
  • 占有且等待:線程獲取到鎖時,如果需要的資源沒有獲取到將一直阻塞等待需要的資源;
  • 不可搶占:獲取鎖的線程持有的資源不能被其他線程搶占;
  • 循環(huán)等待:陷入死鎖等待的線程一定是形成了一個循環(huán)等待環(huán)路。

 

死鎖的檢測

 

如果一個程序一次最多獲得一個鎖,那么就不會發(fā)生死鎖問題,但是開發(fā)中經(jīng)常出現(xiàn)程序需要獲取多個鎖的場景,那么這個時候就必須考慮鎖的順序問題。

如果所有的線程以固定的順序獲取鎖也是不會出現(xiàn)死鎖問題的,當線程試圖以不同的順序來獲取鎖時,死鎖將會發(fā)生。

下面的示例將會發(fā)生死鎖:

public class DeadlockTest {
    //創(chuàng)建兩個鎖對象
    private final Object leftMonitor = new Object();
    private final Object rightMonitor = new Object();
    /**
     * 持有L鎖想要獲取R鎖
     */
    @SneakyThrows
    public void leftForRight() {
        synchronized (leftMonitor){
            //休眠一下,給R加鎖的機會
            TimeUnit.SECONDS.sleep(1);
            synchronized (rightMonitor){
                System.out.println("leftForRight獲取到鎖");
            }
        }
    }

    /**
     * 持有R鎖獲取L鎖
     */
    public void rightForLeft() {
        synchronized (rightMonitor){
            synchronized (leftMonitor){
                System.out.println("rightForLeft獲取到鎖");
            }
        }
    }

    public static void main(String[] args) {
        DeadlockTest deadlockTest = new DeadlockTest();
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.execute(()->{
            deadlockTest.leftForRight();
        });
        executor.execute(()->{
            deadlockTest.rightForLeft();
        });
        executor.shutdown();

    }

}

我們可以通過JDK提供的jstack或者jconsole工具查看死鎖信息。

jstack -l pid查看堆棧信息:

避免死鎖危險

 

或者jconsole連接到進程上:

避免死鎖危險

 


避免死鎖危險

 

通過堆棧信息能夠很直接看到死鎖信息。

linux環(huán)境下dump出堆棧信息的方法我們后續(xù)再聊。

 

死鎖的避免

 

我們可以通過打破死鎖發(fā)生的條件來避免死鎖。

程序中的業(yè)務(wù)要求我們必須使用獨占鎖而不能使用共享鎖,那我們就不能打破鎖的互斥性。

破壞占有且等待:一次性申請所有資源;

破壞不可搶占:使用顯示鎖Lock中的tryLock功能來代替內(nèi)置鎖synchronized,可以檢測死鎖和從死鎖中恢復過來。使用內(nèi)置鎖的線程獲取不到鎖會被阻塞,而顯式鎖可以指定一個超時時限(Timeout),在等待設(shè)置的時間后tryLock就會返回一個失敗信息,也會釋放其擁有的資源。

破壞循環(huán)等待:使線程按照固定的順序獲取鎖,在設(shè)計中我們應(yīng)盡量減少鎖的交互數(shù)量,提前設(shè)計好鎖的順序并嚴格遵守。

 

結(jié)束語

 

并發(fā)編程系列基礎(chǔ)知識的學習到此結(jié)束了,后續(xù)如果遇到相關(guān)的知識再補充。

下一個系列《Java基礎(chǔ)》揚帆啟航,類加載、數(shù)據(jù)結(jié)構(gòu)(包括線程安全的數(shù)據(jù)結(jié)構(gòu))、泛型等知識將與你相遇。

祝大家圣誕節(jié)快樂!!

分享到:
標簽:死鎖
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定