DeadLock 및 그 원인 - 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 메서드를 호출하고 개체의 뮤텍스를 획득한 다음 friend 개체의 뮤텍스를 획득한다고 가정합니다."

"한편 두 번째 스레드는 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를 얻습니다."

"다 괜찮아 보이지만, 두 번째 기사가 동시에 첫 번째 기사를 공격하는 상황이 있을 수 있습니다. 이 방법은 두 번째 기사에도 호출되지만 기사 오브젝트는 다른 순서로 전달됩니다."

"교착 상태에 빠지기 위해 여러 가지 방법이 필요하지 않다는 뜻입니까?"

"맞아요. 때로는 하나의 간단한 방법만 있으면 스레드와 전체 프로그램이 중단됩니다."

"네, 생각보다 이런 현상이 자주 일어나는 것 같아요. 고마워요, 엘리."