16 Java併發性和多執行緒 死鎖

2021-09-20 11:06:01 字數 2423 閱讀 5900

以下內容**

死鎖是兩個或更多執行緒阻塞著等待其它處於死鎖狀態的執行緒所持有的鎖。死鎖通常發生在多個執行緒同時但以不同的順序請求同一組鎖的時候。

例如,如果執行緒1鎖住了a,然後嘗試對b進行加鎖,同時執行緒2已經鎖住了b,接著嘗試對a進行加鎖,這時死鎖就發生了。執行緒1永遠得不到b,執行緒2也永遠得不到a,並且它們永遠也不會知道發生了這樣的事情。為了得到彼此的物件(a和b),它們將永遠阻塞下去。這種情況就是乙個死鎖。

該情況如下:

thread 1  locks a, waits for

bthread 2 locks b, waits for a

這裡有乙個treenode類的例子,它呼叫了不同例項的synchronized方法:

public

class

treenode

}public

synchronized

void

addchildonly(treenode child)

}public

synchronized

void

setparent(treenode parent)

public

synchronized

void

setparentonly(treenode parent)

}

如果執行緒1呼叫parent.addchild(child)方法的同時有另外乙個執行緒2呼叫child.setparent(parent)方法,兩個執行緒中的parent表示的是同乙個物件,child亦然,此時就會發生死鎖。下面的偽**說明了這個過程:

thread 1: parent.addchild(child); //

locks parent

-->child.setparentonly(parent);

thread 2: child.setparent(parent); //

locks child

--> parent.addchildonly()

首先執行緒1呼叫parent.addchild(child)。因為addchild()是同步的,所以執行緒1會對parent物件加鎖以不讓其它執行緒訪問該物件。

然後執行緒2呼叫child.setparent(parent)。因為setparent()是同步的,所以執行緒2會對child物件加鎖以不讓其它執行緒訪問該物件。

現在child和parent物件被兩個不同的執行緒鎖住了。接下來執行緒1嘗試呼叫child.setparentonly()方法,但是由於child物件現在被執行緒2鎖住的,所以該呼叫會被阻塞。執行緒2也嘗試呼叫parent.addchildonly(),但是由於parent物件現在被執行緒1鎖住,導致執行緒2也阻塞在該方法處。現在兩個執行緒都被阻塞並等待著獲取另外乙個執行緒所持有的鎖。

注意:像上文描述的,這兩個執行緒需要同時呼叫parent.addchild(child)和child.setparent(parent)方法,並且是同乙個parent物件和同乙個child物件,才有可能發生死鎖。上面的**可能執行一段時間才會出現死鎖。

這些執行緒需要同時獲得鎖。舉個例子,如果執行緒1稍微領先執行緒2,然後成功地鎖住了a和b兩個物件,那麼執行緒2就會在嘗試對b加鎖的時候被阻塞,這樣死鎖就不會發生。因為執行緒排程通常是不可**的,因此沒有乙個辦法可以準確**什麼時候死鎖會發生,僅僅是可能會發生。

更複雜的死鎖

死鎖可能不止包含2個執行緒,這讓檢測死鎖變得更加困難。下面是4個執行緒發生死鎖的例子:

thread 1  locks a, waits for

bthread 2 locks b, waits for

cthread 3 locks c, waits for

dthread 4 locks d, waits for a

執行緒1等待執行緒2,執行緒2等待執行緒3,執行緒3等待執行緒4,執行緒4等待執行緒1。

資料庫的死鎖

更加複雜的死鎖場景發生在資料庫事務中。乙個資料庫事務可能由多條sql更新請求組成。當在乙個事務中更新一條記錄,這條記錄就會被鎖住避免其他事務的更新請求,直到第乙個事務結束。同乙個事務中每乙個更新請求都可能會鎖住一些記錄。

當多個事務同時需要對一些相同的記錄做更新操作時,就很有可能發生死鎖,例如:

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.

(十五)Java併發性和多執行緒 死鎖

死鎖是兩個或更多執行緒阻塞著等待其它處於死鎖狀態的執行緒所持有的鎖。死鎖通常發生在多個執行緒同時但以不同的順序請求同一組鎖的時候。例如,如果執行緒1鎖住了a,然後嘗試對b進行加鎖,同時執行緒2已經鎖住了b,接著嘗試對a進行加鎖,這時死鎖就發生了。執行緒1永遠得不到b,執行緒2也永遠得不到a,並且它們...

3 Java併發性和多執行緒 多執行緒的代價

以下內容 從乙個單執行緒的應用到乙個多執行緒的應用並不僅僅帶來好處,它也會有一些代價。不要僅僅為了使用多執行緒而使用多執行緒。而應該明確在使用多執行緒時能多來的好處比所付出的代價大的時候,才使用多執行緒。如果存在疑問,應該嘗試測量一下應用程式的效能和響應能力,而不只是猜測。設計更複雜 雖然有一些多執...

Java多執行緒 死鎖

死鎖 不同的執行緒分別占用對方需要的同步資源不放棄,都在等待對方放棄自己的需要的同步資源,就形成了執行緒的死鎖 解決方法 1.專門的演算法 原則 2.儘量減少同步資源的定義 此處插入testdeadlock 死鎖問題,處理執行緒同步時容易出現 public class testdeadlock ca...