成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

淺談死鎖原理

int64 / 2563人閱讀

摘要:死鎖通常發(fā)生在多個(gè)線程同時(shí)但以不同的順序請(qǐng)求同一組鎖的時(shí)候?,F(xiàn)在和對(duì)象被兩個(gè)不同的線程鎖住了。更復(fù)雜的死鎖死鎖可能不止包含個(gè)線程,這讓檢測(cè)死鎖變得更加困難。

死鎖是兩個(gè)或更多線程阻塞著等待其它處于死鎖狀態(tài)的線程所持有的鎖。死鎖通常發(fā)生在多個(gè)線程同時(shí)但以不同的順序請(qǐng)求同一組鎖的時(shí)候。

例如,如果線程1鎖住了A,然后嘗試對(duì)B進(jìn)行加鎖,同時(shí)線程2已經(jīng)鎖住了B,接著嘗試對(duì)A進(jìn)行加鎖,這時(shí)死鎖就發(fā)生了。線程1永遠(yuǎn)得不到B,線程2也永遠(yuǎn)得不到A,并且它們永遠(yuǎn)也不會(huì)知道發(fā)生了這樣的事情。為了得到彼此的對(duì)象(A和B),它們將永遠(yuǎn)阻塞下去。這種情況就是一個(gè)死鎖。

該情況如下:

Thread 1  locks A, waits for B
Thread 2  locks B, waits for A

這里有一個(gè)TreeNode類的例子,它調(diào)用了不同實(shí)例的synchronized方法:

public class TreeNode {
    TreeNode parent   = null;  
    List children = new ArrayList();

    public synchronized void addChild(TreeNode child){
        if(!this.children.contains(child)) {
            this.children.add(child);
            child.setParentOnly(this);
        }
    }

    public synchronized void addChildOnly(TreeNode child){
        if(!this.children.contains(child){
            this.children.add(child);
        }
    }

    public synchronized void setParent(TreeNode parent){
        this.parent = parent;
        parent.addChildOnly(this);
    }

    public synchronized void setParentOnly(TreeNode parent){
        this.parent = parent;
    }
}

如果線程1調(diào)用parent.addChild(child)方法的同時(shí)有另外一個(gè)線程2調(diào)用child.setParent(parent)方法,兩個(gè)線程中的parent表示的是同一個(gè)對(duì)象,child亦然,此時(shí)就會(huì)發(fā)生死鎖。下面的偽代碼說(shuō)明了這個(gè)過(guò)程:

Thread 1: parent.addChild(child); //locks parent
          --> child.setParentOnly(parent);

Thread 2: child.setParent(parent); //locks child
          --> parent.addChildOnly()

首先線程1調(diào)用parent.addChild(child)。因?yàn)閍ddChild()是同步的,所以線程1會(huì)對(duì)parent對(duì)象加鎖以不讓其它線程訪問(wèn)該對(duì)象。

然后線程2調(diào)用child.setParent(parent)。因?yàn)閟etParent()是同步的,所以線程2會(huì)對(duì)child對(duì)象加鎖以不讓其它線程訪問(wèn)該對(duì)象。

現(xiàn)在child和parent對(duì)象被兩個(gè)不同的線程鎖住了。接下來(lái)線程1嘗試調(diào)用child.setParentOnly()方法,但是由于child對(duì)象現(xiàn)在被線程2鎖住的,所以該調(diào)用會(huì)被阻塞。線程2也嘗試調(diào)用parent.addChildOnly(),但是由于parent對(duì)象現(xiàn)在被線程1鎖住,導(dǎo)致線程2也阻塞在該方法處?,F(xiàn)在兩個(gè)線程都被阻塞并等待著獲取另外一個(gè)線程所持有的鎖。

注意:像上文描述的,這兩個(gè)線程需要同時(shí)調(diào)用parent.addChild(child)和child.setParent(parent)方法,并且是同一個(gè)parent對(duì)象和同一個(gè)child對(duì)象,才有可能發(fā)生死鎖。上面的代碼可能運(yùn)行一段時(shí)間才會(huì)出現(xiàn)死鎖。

這些線程需要同時(shí)獲得鎖。舉個(gè)例子,如果線程1稍微領(lǐng)先線程2,然后成功地鎖住了A和B兩個(gè)對(duì)象,那么線程2就會(huì)在嘗試對(duì)B加鎖的時(shí)候被阻塞,這樣死鎖就不會(huì)發(fā)生。因?yàn)榫€程調(diào)度通常是不可預(yù)測(cè)的,因此沒有一個(gè)辦法可以準(zhǔn)確預(yù)測(cè)什么時(shí)候死鎖會(huì)發(fā)生,僅僅是可能會(huì)發(fā)生。

更復(fù)雜的死鎖

死鎖可能不止包含2個(gè)線程,這讓檢測(cè)死鎖變得更加困難。下面是4個(gè)線程發(fā)生死鎖的例子:

Thread 1  locks A, waits for B
Thread 2  locks B, waits for C
Thread 3  locks C, waits for D
Thread 4  locks D, waits for A

線程1等待線程2,線程2等待線程3,線程3等待線程4,線程4等待線程1。

數(shù)據(jù)庫(kù)的死鎖

更加復(fù)雜的死鎖場(chǎng)景發(fā)生在數(shù)據(jù)庫(kù)事務(wù)中。一個(gè)數(shù)據(jù)庫(kù)事務(wù)可能由多條SQL更新請(qǐng)求組成。當(dāng)在一個(gè)事務(wù)中更新一條記錄,這條記錄就會(huì)被鎖住避免其他事務(wù)的更新請(qǐng)求,直到第一個(gè)事務(wù)結(jié)束。同一個(gè)事務(wù)中每一個(gè)更新請(qǐng)求都可能會(huì)鎖住一些記錄。

當(dāng)多個(gè)事務(wù)同時(shí)需要對(duì)一些相同的記錄做更新操作時(shí),就很有可能發(fā)生死鎖,例如:

Transaction 1, request 1, locks record 1 for update
Transaction 2, request 1, locks record 2 for update
Transaction 1, request 2, tries to lock record 2 for update.
Transaction 2, request 2, tries to lock record 1 for update.

因?yàn)殒i發(fā)生在不同的請(qǐng)求中,并且對(duì)于一個(gè)事務(wù)來(lái)說(shuō)不可能提前知道所有它需要的鎖,因此很難檢測(cè)和避免數(shù)據(jù)庫(kù)事務(wù)中的死鎖。


原文 Deadlock
譯者 申章
校對(duì) 丁一
via ifeve.com

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/17436.html

相關(guān)文章

  • 淺談Java中鎖的問(wèn)題

    摘要:之前我們簡(jiǎn)單的討論了一下關(guān)于中的同步還有一些鎖優(yōu)化的問(wèn)題,今天我們就來(lái)簡(jiǎn)單的聊一聊關(guān)于中的死鎖問(wèn)題。這里顯示兩個(gè)線程的狀態(tài)現(xiàn)在是處于阻塞狀態(tài),然后都在等待鎖的獲取,我們?cè)倮^續(xù)往下看。 之前我們簡(jiǎn)單的討論了一下關(guān)于Java中的同步還有一些鎖優(yōu)化的問(wèn)題,今天我們就來(lái)簡(jiǎn)單的聊一聊關(guān)于Java中的死鎖問(wèn)題。 這個(gè)問(wèn)題我們?cè)陂_發(fā)的時(shí)候,或多或少都能遇到,對(duì)業(yè)務(wù)邏輯沒有正確的梳理,又或者是在多線程...

    fox_soyoung 評(píng)論0 收藏0
  • Java并發(fā)核心淺談

    摘要:耐心看完的你或多或少會(huì)有收獲并發(fā)的核心就是包,而的核心是抽象隊(duì)列同步器,簡(jiǎn)稱,一些鎖啊信號(hào)量啊循環(huán)屏障啊都是基于。 耐心看完的你或多或少會(huì)有收獲! Java并發(fā)的核心就是 java.util.concurrent 包,而 j.u.c 的核心是AbstractQueuedSynchronizer抽象隊(duì)列同步器,簡(jiǎn)稱 AQS,一些鎖??!信號(hào)量?。⊙h(huán)屏障??!都是基于AQS。而 AQS 又是...

    cppowboy 評(píng)論0 收藏0
  • 淺談Java并發(fā)編程系列(八)—— LockSupport原理剖析

    摘要:此對(duì)象在線程受阻塞時(shí)被記錄,以允許監(jiān)視工具和診斷工具確定線程受阻塞的原因。阻塞當(dāng)前線程,最長(zhǎng)不超過(guò)納秒,返回條件在的基礎(chǔ)上增加了超時(shí)返回。喚醒線程喚醒處于阻塞狀態(tài)的線程。 LockSupport 用法簡(jiǎn)介 LockSupport 和 CAS 是Java并發(fā)包中很多并發(fā)工具控制機(jī)制的基礎(chǔ),它們底層其實(shí)都是依賴Unsafe實(shí)現(xiàn)。 LockSupport是用來(lái)創(chuàng)建鎖和其他同步類的基本線程阻塞...

    jeyhan 評(píng)論0 收藏0
  • 淺談java中的并發(fā)控制

    摘要:并發(fā)需要解決的問(wèn)題功能性問(wèn)題線程同步面臨兩個(gè)問(wèn)題,想象下有兩個(gè)線程在協(xié)作工作完成某項(xiàng)任務(wù)。鎖可用于規(guī)定一個(gè)臨界區(qū),同一時(shí)間臨界區(qū)內(nèi)僅能由一個(gè)線程訪問(wèn)。并發(fā)的數(shù)據(jù)結(jié)構(gòu)線程安全的容器,如等。 并發(fā)指在宏觀上的同一時(shí)間內(nèi)同時(shí)執(zhí)行多個(gè)任務(wù)。為了滿足這一需求,現(xiàn)代的操作系統(tǒng)都抽象出 線程 的概念,供上層應(yīng)用使用。 這篇博文不打算詳細(xì)展開分析,而是對(duì)java并發(fā)中的概念和工具做一個(gè)梳理。沿著并發(fā)模...

    Gilbertat 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<