<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:手寫一個(gè)必然死鎖的例子

          共 4280字,需瀏覽 9分鐘

           ·

          2021-10-21 10:45

          閱讀本文大概需要 5 分鐘。

          來自:blog.csdn.net/xiewenfeng520/article/details/107230996

          前言

          只對(duì)死鎖代碼感興趣的可以直接跳到第三小節(jié) 必然死鎖示例,如果對(duì)死鎖還不太了解的,我們可以一起來討論以下幾個(gè)議題
          • 什么是死鎖?
          • 死鎖有什么危害和特點(diǎn)?
          • 代碼實(shí)現(xiàn)一個(gè)必然死鎖的示例
          • 分析死鎖的過程
          推薦下自己做的 Spring Boot 的實(shí)戰(zhàn)項(xiàng)目:
          https://github.com/YunaiV/ruoyi-vue-pro

          項(xiàng)目環(huán)境

          • jdk 1.8

          • github 地址:https://github.com/huajiexiewenfeng/java-concurrent


            • 本章模塊:deadlock
          推薦下自己做的 Spring Cloud 的實(shí)戰(zhàn)項(xiàng)目:
          https://github.com/YunaiV/onemall

          1.什么是死鎖?

          關(guān)鍵詞:并發(fā)場景,多線程
          首先我們需要知道,死鎖一定發(fā)生在并發(fā)場景中。我們?yōu)榱吮WC線程安全,有時(shí)會(huì)給程序使用各種能保證并發(fā)安全的工具,尤其是鎖,但是如果在使用過程中處理不得當(dāng),就有可能會(huì)導(dǎo)致發(fā)生死鎖的情況。
          關(guān)鍵詞:互不相讓
          死鎖是一種狀態(tài),當(dāng)兩個(gè)(或多個(gè))線程(或進(jìn)程)相互持有對(duì)方所需要的資源,卻又都不主動(dòng)釋放自己手中所持有的資源,導(dǎo)致大家都獲取不到自己想要的資源,所有相關(guān)的線程(或進(jìn)程)都無法繼續(xù)往下執(zhí)行,在未改變這種狀態(tài)之前都不能向前推進(jìn),我們就把這種狀態(tài)稱為死鎖狀態(tài),認(rèn)為它們發(fā)生了死鎖。
          簡而言之,死鎖就是兩個(gè)或多個(gè)線程(或進(jìn)程)被無限期地阻塞,相互等待對(duì)方手中資源的一種狀態(tài)。
          兩個(gè)線程死鎖的情況
          如圖所示,線程1 已經(jīng)持有了 鎖1,同時(shí) 線程2 也已經(jīng)持有了鎖2,然后 線程1 嘗試獲取 鎖2,但是 線程2 并沒有釋放 鎖2,所以 線程1 處于阻塞狀態(tài),同理可知,圖中的 線程2 獲取 鎖1也會(huì)被阻塞。
          這樣一來,線程1 和 線程2 就發(fā)生了死鎖,因?yàn)樗鼈兌枷嗷コ钟袑?duì)方想要的資源,卻又不釋放自己手中的資源,形成相互等待,而且會(huì)一直等待下去。

          2.死鎖的影響和危害

          2.1 死鎖的影響

          死鎖的影響在不同系統(tǒng)中是不一樣的,影響的大小一部分取決于當(dāng)前這個(gè)系統(tǒng)或者環(huán)境對(duì)死鎖的處理能力。
          2.1.1 數(shù)據(jù)庫中
          例如,在數(shù)據(jù)庫系統(tǒng)軟件的設(shè)計(jì)中,考慮了監(jiān)測死鎖以及從死鎖中恢復(fù)的情況。在執(zhí)行一個(gè)事務(wù)的時(shí)候可能需要獲取多把鎖,并一直持有這些鎖直到事務(wù)完成。在某個(gè)事務(wù)中持有的鎖可能在其他事務(wù)中也需要,因此在兩個(gè)事務(wù)之間有可能發(fā)生死鎖的情況,一旦發(fā)生了死鎖,如果沒有外部干涉,那么兩個(gè)事務(wù)就會(huì)永遠(yuǎn)的等待下去。
          但數(shù)據(jù)庫系統(tǒng)不會(huì)放任這種情況發(fā)生,當(dāng)數(shù)據(jù)庫檢測到這一組事務(wù)發(fā)生了死鎖時(shí),根據(jù)策略的不同,可能會(huì)選擇放棄某一個(gè)事務(wù),被放棄的事務(wù)就會(huì)釋放掉它所持有的鎖,從而使其他的事務(wù)繼續(xù)順利進(jìn)行。
          此時(shí)程序可以重新執(zhí)行被強(qiáng)行終止的事務(wù),而這個(gè)事務(wù)現(xiàn)在就可以順利執(zhí)行了,因?yàn)樗懈偁庂Y源的事務(wù)都已經(jīng)在剛才執(zhí)行完畢,并且釋放資源了。
          2.1.2 JVM 中
          在 JVM 中,對(duì)于死鎖的處理能力就不如數(shù)據(jù)庫那么強(qiáng)大了。如果在 JVM 中發(fā)生了死鎖,JVM 并不會(huì)自動(dòng)進(jìn)行處理,所以一旦死鎖發(fā)生,就會(huì)陷入無窮的等待。

          2.2 死鎖的危害以及特點(diǎn)

          關(guān)鍵詞:概率性事件
          死鎖的問題和其他的并發(fā)安全問題一樣,是概率性的,也就是說,即使存在發(fā)生死鎖的可能性,也并不是 100% 會(huì)發(fā)生的。如果每個(gè)鎖的持有時(shí)間很短,那么發(fā)生沖突的概率就很低,所以死鎖發(fā)生的概率也很低。但是在線上系統(tǒng)里,可能每天有幾千萬次的“獲取鎖”、“釋放鎖”操作,在巨量的次數(shù)面前,整個(gè)系統(tǒng)發(fā)生問題的幾率就會(huì)被放大,只要有某幾次操作是有風(fēng)險(xiǎn)的,就可能會(huì)導(dǎo)致死鎖的發(fā)生。
          也正是因?yàn)樗梨i“不一定會(huì)發(fā)生”的特點(diǎn),導(dǎo)致提前找出死鎖成為了一個(gè)難題。壓力測試雖然可以檢測出一部分可能發(fā)生死鎖的情況,但是并不足以完全模擬真實(shí)、長期運(yùn)行的場景,因此沒有辦法把所有潛在可能發(fā)生死鎖的代碼都找出來。
          關(guān)鍵詞:危害大,發(fā)生幾率不高
          一旦發(fā)生了死鎖,根據(jù)發(fā)生死鎖的線程的職責(zé)不同,就可能會(huì)造成 子系統(tǒng)崩潰、性能降低 甚至 整個(gè)系統(tǒng)崩潰 等各種不良后果。而且死鎖往往發(fā)生在高并發(fā)、高負(fù)載的情況下,因?yàn)榭赡軙?huì)直接影響到很多用戶,造成一系列的問題。以上就是死鎖發(fā)生幾率不高但是危害大的特點(diǎn)。

          3.必然死鎖示例

          public?class?MustDeadLockDemo?{

          ????public?static?void?main(String[]?args)?{
          ????????Object?lock1?=?new?Object();
          ????????Object?lock2?=?new?Object();
          ????????new?Thread(new?DeadLockTask(lock1,?lock2,?true),?"線程1").start();
          ????????new?Thread(new?DeadLockTask(lock1,?lock2,?false),?"線程2").start();

          ????}

          ????static?class?DeadLockTask?implements?Runnable?{

          ????????private?boolean?flag;
          ????????private?Object?lock1;
          ????????private?Object?lock2;

          ????????public?DeadLockTask(Object?lock1,?Object?lock2,?boolean?flag)?{
          ????????????this.lock1?=?lock1;
          ????????????this.lock2?=?lock2;
          ????????????this.flag?=?flag;
          ????????}

          ????????@Override
          ????????public?void?run()?{
          ????????????if?(flag)?{
          ????????????????synchronized?(lock1)?{
          ????????????????????System.out.println(Thread.currentThread().getName()?+?"->拿到鎖1");
          ????????????????????try?{
          ????????????????????????Thread.sleep(1000);
          ????????????????????}?catch?(InterruptedException?e)?{
          ????????????????????????e.printStackTrace();
          ????????????????????}
          ????????????????????System.out.println(Thread.currentThread().getName()?+?"->等待鎖2釋放...");
          ????????????????????synchronized?(lock2)?{
          ????????????????????????System.out.println(Thread.currentThread().getName()?+?"->拿到鎖2");
          ????????????????????}
          ????????????????}
          ????????????}
          ????????????if?(!flag)?{
          ????????????????synchronized?(lock2)?{
          ????????????????????System.out.println(Thread.currentThread().getName()?+?"->拿到鎖2");
          ????????????????????try?{
          ????????????????????????Thread.sleep(1000);
          ????????????????????}?catch?(InterruptedException?e)?{
          ????????????????????????e.printStackTrace();
          ????????????????????}
          ????????????????????System.out.println(Thread.currentThread().getName()?+?"->等待鎖1釋放...");
          ????????????????????synchronized?(lock1)?{
          ????????????????????????System.out.println(Thread.currentThread().getName()?+?"->拿到鎖1");
          ????????????????????}
          ????????????????}
          ????????????}
          ????????}
          ????}
          }

          執(zhí)行結(jié)果:
          可以看到程序一直處于阻塞狀態(tài)。

          4.過程分析

          其實(shí)上面的代碼示例發(fā)生死鎖的過程就是第一小節(jié)中 兩個(gè)線程發(fā)生死鎖 的情況,這里我們把圖拿過來,方便分析。
          本文使用 IDEA 進(jìn)行調(diào)試,將斷點(diǎn)打在 33 行,run方法的第一行,選擇 Thread 模式。
          注意:調(diào)試過程,因?yàn)橛腥藶榈牡却龝r(shí)間,所以并不會(huì)發(fā)生死鎖,這里只是演示線程執(zhí)行的順序和狀態(tài)。
          第一步,線程1進(jìn)入,flag = true,進(jìn)入第一個(gè) synchronized 同步塊,拿到 lock1(鎖1)
          第二步,直接點(diǎn)擊 Resume Program(F9),進(jìn)入線程2,此時(shí) flag = false,進(jìn)入第二個(gè) synchronized 同步塊
          當(dāng)然如果 Thread.sleep 的時(shí)間夠長,或者操作速度夠快的話,也能發(fā)生死鎖。

          5.總結(jié)

          本章我們討論了什么是死鎖,以及死鎖的影響和危害,演示了一個(gè)必然死鎖的例子,然后使用 IDEA 工具調(diào)試了兩個(gè)線程發(fā)生死鎖的步驟。
          在 JVM 中如果發(fā)生死鎖,可能會(huì)導(dǎo)致程序部分甚至全部無法繼續(xù)向下執(zhí)行的情況,所以死鎖在 JVM 中所帶來的危害和影響是比較大的,我們需要盡量避免。
          最后如果在面試中碰到這一題,希望大家都能順利通過。
          瀏覽 34
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品99久久久久久猫咪 | 五月天婷婷丁香久久 | 人人看人人摸人人操天天看天天摸天天操 | 国产美女自拍 | 欧美综合一区二区 |