死鎖及其原因 - 1

“嗨,阿米戈!”

“今天我要告訴你什麼是死鎖。”

“嘿,你已經和我說過類似的事情了。”

“是的,我做到了。但今天我們將更詳細地考慮這個話題。”

“在最簡單的情況下,死鎖涉及兩個線程和兩個互斥對象。互鎖發生在:”

A)每個線程都需要獲取兩個互斥量。

B) 第一個線程已經獲取了第一個互斥鎖,正在等待第二個互斥鎖被釋放。

C) 第二個線程獲得了第二個互斥體,正在等待第一個互斥體被釋放。

“這裡有些例子:

例子
 public class Student
{
 private ArrayList friends = new ArrayList();

 public synchronized ArrayList getFriends()
 {
  synchronized(friends)
  {
   return new ArrayList(friends);
  }
 }

 public synchronized int getFriendsCount()
 {
  return friends.size();
 }

 public int addFriend(Student student)
 {
  synchronized(friends)
  {
   friends.add(student)
   return getFriendsCount ();
  }
 }
}

“假設一個線程調用getFriends方法,獲取this對象的互斥量,然後獲取friends對象的互斥量。”

“與此同時,第二個線程調用addFriend方法,獲取好友對象的互斥量,然後獲取此對象的互斥量(在調用getFriendsCount期間)。”

“起初,一切都會好起來的,但正如墨菲定律所說:任何可能出錯的事情都會出錯。不可避免地會出現第一個線程只有時間獲取一個互斥鎖,而第二個線程將獲取第二個互斥鎖的情況就在那一刻互斥鎖。它們會像那樣掛起,永遠等待另一個線程釋放互斥鎖。”

“我決定引用我在書中找到的另一個簡單例子:”

例子
class KnightUtil
{
 public static void kill(Knight knight1, Knight knight2)
 {
  synchronized(knight1)
  {
   synchronized(knight2)
   {
    knight2.live = 0;
    knight1.experience += 100;
   }
  }
 }
}

”有一個遊戲,兩個騎士在打架。一個騎士殺死了另一個。這種行為體現在 kill方法中。將兩個騎士對像傳遞給它。

“首先,我們保護這兩個對象,這樣其他人就無法更改它們。”

“第二個騎士死了(HP = 0)”

“第一個騎士獲得 100 XP。”

“一切似乎都很好,但可能會出現第二個騎士同時攻擊第一個騎士的情況。第二個騎士也調用了這種方法,但騎士對象的傳遞順序不同。”

“你的意思是我們甚至不需要多種方法來陷入僵局?”

“是的。有時只需要一種簡單的方法就會導致線程和整個程序掛起。”

“是啊,我想這種現像比我想像的更頻繁發生。謝謝,艾莉。”