DeadLock và nguyên nhân - 1

"Chào, Amigo!"

"Hôm nay tôi sẽ cho bạn biết bế tắc là gì."

“Này, cậu đã nói với tớ về một chuyện như thế rồi mà.”

"Vâng, tôi đã làm. Nhưng hôm nay chúng ta sẽ xem xét chủ đề này chi tiết hơn."

"Trong trường hợp đơn giản nhất, bế tắc liên quan đến hai luồng và hai đối tượng mutex. Khóa lẫn nhau xảy ra khi:"

A) Mỗi ​​luồng cần có cả hai bộ chuyển đổi.

B)  Chuỗi đầu tiên đã nhận được mutex đầu tiên và đang chờ cái thứ hai được giải phóng.

C)  Chuỗi thứ hai đã nhận được mutex thứ hai và đang đợi cái đầu tiên được giải phóng.

"Đây là một số ví dụ:

Ví dụ
 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 ();
  }
 }
}

"Giả sử một luồng gọi phương thức getFriends , lấy mutex của đối tượng này , sau đó lấy mutex của đối tượng bạn bè ."

"Trong khi đó, luồng thứ hai gọi phương thức addFriend , lấy mutex của đối tượng bạn bè và sau đó lấy mutex của đối tượng này (trong khi gọi getFriendsCount )."

"Lúc đầu, mọi thứ sẽ ổn, nhưng như Định luật Murphy tuyên bố: bất cứ điều gì có thể sai sẽ sai. Một tình huống chắc chắn sẽ phát sinh trong đó luồng đầu tiên sẽ chỉ có thời gian để có được một mutex và luồng thứ hai sẽ có được thứ hai mutex ngay tại thời điểm đó. Chúng sẽ bị treo như vậy, mãi mãi chờ luồng khác giải phóng mutex."

"Tôi đã quyết định trích dẫn một ví dụ đơn giản khác mà tôi tìm thấy trong một cuốn sách:"

Ví dụ
class KnightUtil
{
 public static void kill(Knight knight1, Knight knight2)
 {
  synchronized(knight1)
  {
   synchronized(knight2)
   {
    knight2.live = 0;
    knight1.experience += 100;
   }
  }
 }
}

"Có một trò chơi mà hai hiệp sĩ đánh nhau. Một hiệp sĩ giết hiệp sĩ kia. Hành vi này được phản ánh trong phương thức giết . Hai đối tượng hiệp sĩ được chuyển cho nó.

"Đầu tiên, chúng tôi bảo vệ cả hai đối tượng để không ai khác có thể thay đổi chúng."

"Hiệp sĩ thứ hai chết (HP = 0)"

"Hiệp sĩ đầu tiên nhận được 100 XP."

"Mọi thứ có vẻ ổn, nhưng có thể có những tình huống mà hiệp sĩ thứ hai tấn công hiệp sĩ đầu tiên cùng một lúc. Phương pháp này cũng được gọi cho hiệp sĩ thứ hai, nhưng các đối tượng hiệp sĩ được chuyển theo một thứ tự khác."

"Ý bạn là chúng ta thậm chí không cần nhiều phương pháp để giải quyết bế tắc?"

"Phải. Đôi khi chỉ cần một phương pháp đơn giản là có thể khiến các luồng và toàn bộ chương trình bị treo."

"Ừ, tôi đoán hiện tượng này xảy ra thường xuyên hơn tôi nghĩ. Cảm ơn, Ellie."