간단한 교착 상태 예


92

스레딩 교착 상태를 초보자에게 설명하고 싶습니다. 나는 과거에 교착 상태에 대한 많은 예를 보았습니다. 일부는 코드를 사용하고 일부는 일러스트레이션을 사용했습니다 (유명한 4 대의 자동차 ). The Dining Philosophers 와 같이 쉽게 교착 상태가되는 고전적인 문제도 있지만 실제 초보자가 완전히 파악하기에는 너무 복잡 할 수 있습니다.

교착 상태를 설명하기 위해 가장 간단한 코드 예제를 찾고 있습니다. 예제는 다음과 같아야합니다.

  1. 의미있는 "실제"프로그래밍 시나리오와 관련이 있습니다.
  2. 매우 짧고 단순하며 직설적이어야합니다.

추천 메뉴가 무엇인가요?


나에게 매우 간단 해 보이기 때문에 유명한 4 대의 자동차를 사용하는 것은 어떨까요?
vehomzzz

2
4 대의 자동차는 프로그래밍 시나리오가 아니며 초보자가 4 대의 자동차 형태로 문제를 추상화하는 것은 사소한 일이 아닙니다. 나는 그것들을 사용하지만 교착 상태가 발생하는 프로그래밍 시나리오를 보여주고 싶습니다.
Roee Adler

답변:


139

간단한 은행 상황 일 수도 있습니다.

class Account {
  double balance;

  void withdraw(double amount){
     balance -= amount;
  } 

  void deposit(double amount){
     balance += amount;
  } 

   void transfer(Account from, Account to, double amount){
        sync(from);
        sync(to);

        from.withdraw(amount);
        to.deposit(amount);

        release(to);
        release(from);
    }

}

분명히, transfer ( a, b ) 및 transfer ( b, a )를 동시에 실행한다면, 그들이 역순으로 자원을 획득하려고하기 때문에 교착 상태가 발생할 것입니다.

이 코드는 교착 상태에 대한 솔루션을 찾는 데에도 좋습니다. 도움이 되었기를 바랍니다!


1
귀하 또는 다른 사람이이 문제에 대한 해결책을 제공 할 수 있다면 완벽 할 것입니다.
Jacky

2
이 문제에 대한 @Jacky 솔루션은 Will Hartung이 여기에 게시했습니다. stackoverflow.com/questions/13326861/avoid-deadlock-example/…
Piotr Chojnacki

2
나는 당신의 구문에 혼란스러워합니다. sync () 메서드는 무엇입니까? 나는 sync (from); ... release (from); 동기화 (from) {...}로 대체되었습니다.
Ellen Spertus 2014 년

1
@espertus sync는 다음과 같을 수 있습니다 sync(Account & a) { a.mutex.lock(); }..
vladon

1
javaworld.com/article/2075692/java-concurrency/… (Brian Goetz)가이 문제에 대한 해결책을 설명합니다.
lingareddyk

59

자연이 교착 상태를 설명하게하십시오.

교착 상태 : 개구리 대 뱀

"나는 그들이 각자의 길을가는 것을보고 싶었지만 나는 지쳤다"고 사진가는 말했다. "개구리는 항상 떼어 내려고 노력 했지만 뱀 은 놓아주지 않았습니다 . " .

여기에 이미지 설명 입력


59
귀엽지 만 프로그래밍 컨텍스트에서 교착 상태가 어떻게 발생하는지 설명하지 않습니다.
jalf

그래 jalf, 적어도 당신은 반대표를 정당화했습니다. 어쨌든 "4 대 자동차"예제와 비슷합니다. 귀여운 교착 상태가 어떻게 보이는지의 표현입니다.
Nick Dandoulakis

@Nick Dandoulakis : 훌륭한 화보 발표. 그림은 교착 상태의 개념을 설명합니다
Rasmi Ranjan Nayak

@NickDandoulakis-좋은 그림이 아닙니다. 여기서 간단한 코드가 도움이 될 것입니다.
Erran Morad 2014-06-12

13
이게 어떻게 귀여워요? 독사와 개구리가 서로를 잡아 먹고 무섭습니다 !!!
vikkyhacks 2014 년

53

다음 은 리소스 잠금을 사용하는 간단한 Java 예제를 보여주는 대만 대학 컴퓨터 과학과 의 코드 예제입니다 . 그것은 나에게 매우 "실제"와 관련이 있습니다. 아래 코드 :

/**
 * Adapted from The Java Tutorial
 * Second Edition by Campione, M. and
 * Walrath, K.Addison-Wesley 1998
 */

/**
 * This is a demonstration of how NOT to write multi-threaded programs.
 * It is a program that purposely causes deadlock between two threads that
 * are both trying to acquire locks for the same two resources.
 * To avoid this sort of deadlock when locking multiple resources, all threads
 * should always acquire their locks in the same order.
 **/
public class Deadlock {
  public static void main(String[] args){
    //These are the two resource objects 
    //we'll try to get locks for
    final Object resource1 = "resource1";
    final Object resource2 = "resource2";
    //Here's the first thread.
    //It tries to lock resource1 then resource2
    Thread t1 = new Thread() {
      public void run() {
        //Lock resource 1
        synchronized(resource1){
          System.out.println("Thread 1: locked resource 1");
          //Pause for a bit, simulating some file I/O or 
          //something. Basically, we just want to give the 
          //other thread a chance to run. Threads and deadlock
          //are asynchronous things, but we're trying to force 
          //deadlock to happen here...
          try{ 
            Thread.sleep(50); 
          } catch (InterruptedException e) {}

          //Now wait 'till we can get a lock on resource 2
          synchronized(resource2){
            System.out.println("Thread 1: locked resource 2");
          }
        }
      }
    };

    //Here's the second thread.  
    //It tries to lock resource2 then resource1
    Thread t2 = new Thread(){
      public void run(){
        //This thread locks resource 2 right away
        synchronized(resource2){
          System.out.println("Thread 2: locked resource 2");
          //Then it pauses, for the same reason as the first 
          //thread does
          try{
            Thread.sleep(50); 
          } catch (InterruptedException e){}

          //Then it tries to lock resource1.  
          //But wait!  Thread 1 locked resource1, and 
          //won't release it till it gets a lock on resource2.  
          //This thread holds the lock on resource2, and won't
          //release it till it gets resource1.  
          //We're at an impasse. Neither thread can run, 
          //and the program freezes up.
          synchronized(resource1){
            System.out.println("Thread 2: locked resource 1");
          }
        }
      }
    };

    //Start the two threads. 
    //If all goes as planned, deadlock will occur, 
    //and the program will never exit.
    t1.start(); 
    t2.start();
  }
}

1
문제는 이것이 실제로 "실제"사례가 아니라는 것입니다. 이것은 "리소스 1"과 "리소스 2"에 관한 것이고, 이것을 실제 프로그래밍 문제와 실제로 연관시키는 것이 좋을 것입니다 (즉, 문제 도메인 등을 참조하여 실제로 직접 사용할 수 있음을 의미합니다)
Jay

7
제 생각에는 좋은 예입니다. 감사.
James Raitsev

이 코드는 몇 권의 다른 책에 게시 된 것 같습니다. stackoverflow.com/a/11338853/112705
Dan J

15

method1 ()과 method2 ()가 둘 다 또는 여러 스레드에 의해 호출 될 경우, thread 1이 method1 ()을 실행하는 동안 String 객체에 대한 잠금을 획득하고 thread 2가 method2를 실행하는 동안 Integer 객체에 대한 잠금을 획득하기 때문에 교착 상태가 발생할 가능성이 높습니다. () 둘 ​​다 Integer와 String에 대한 잠금을 해제하기 위해 서로가 더 이상 진행할 때까지 기다릴 것입니다.

public void method1() {
    synchronized (String.class) {
        System.out.println("Acquired lock on String.class object");

        synchronized (Integer.class) {
            System.out.println("Acquired lock on Integer.class object");
        }
    }
}

public void method2() {
    synchronized (Integer.class) {
        System.out.println("Acquired lock on Integer.class object");

        synchronized (String.class) {
            System.out.println("Acquired lock on String.class object");
        }
    }
}

빠르고 간단합니다. 좋은.
user1068352

13

내가 본 간단한 교착 상태의 예 중 하나입니다.

public class SimpleDeadLock {
   public static Object l1 = new Object();
   public static Object l2 = new Object();
   private int index;
   public static void main(String[] a) {
      Thread t1 = new Thread1();
      Thread t2 = new Thread2();
      t1.start();
      t2.start();
   }
   private static class Thread1 extends Thread {
      public void run() {
         synchronized (l1) {
            System.out.println("Thread 1: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");
            synchronized (l2) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   }
   private static class Thread2 extends Thread {
      public void run() {
         synchronized (l2) {
            System.out.println("Thread 2: Holding lock 2...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 1...");
            synchronized (l1) {
               System.out.println("Thread 2: Holding lock 2 & 1...");
            }
         }
      }
   }
}

나는 그 예를 좋아합니다. 그러나 SimpleDeadLock 클래스가 Thread에서 확장되는 이유는 무엇입니까? 그것은 필요하지 않습니다.
Charmin

1
이것은이 답변과 거의 같습니다 : stackoverflow.com/a/1385868/1310566 . 그리고 private int index거기서 무엇을 하고 있습니까?
Simon Forsberg 2015 년

6

다음은 C ++ 11의 간단한 예입니다.

#include <mutex>    // mutex
#include <iostream> // cout 
#include <cstdio>   // getchar
#include <thread>   // this_thread, yield
#include <future>   // async
#include <chrono>   // seconds

using namespace std;
mutex _m1;
mutex _m2;

// Deadlock will occur because func12 and func21 acquires the two locks in reverse order

void func12()
{
    unique_lock<mutex> l1(_m1);
    this_thread::yield(); // hint to reschedule
    this_thread::sleep_for( chrono::seconds(1) );
    unique_lock<mutex> l2(_m2 );
}

void func21()
{
    unique_lock<mutex> l2(_m2);
    this_thread::yield(); // hint to reschedule
    this_thread::sleep_for( chrono::seconds(1) );
    unique_lock<mutex> l1(_m1);
}

int main( int argc, char* argv[] )
{
    async(func12);
    func21();
    cout << "All done!"; // this won't be executed because of deadlock
    getchar();
}

5

이 질문에 대한 내 대답을 참조하십시오 . 결론적으로 두 스레드가 두 개의 서로 다른 리소스를 획득해야 할 때마다 다른 순서로 그렇게하면 교착 상태가 발생할 수 있습니다.


2
여기에 다른 답변의 정보를 복제하는 것이 실제로 요점을 보지 못합니다. 이 답변이 개선 될 수 있다고 생각하면 자유롭게 수정할 수 있다고 가정합니다.
djna

이 상황을 "잠금 반전"이라고 생각합니다. 글쎄, 나는 그것을 잠금 반전이라고 부르는 것을 알고 있습니다. 왜냐하면 나는 그것을 그렇게 부르기 때문입니다. 그러나 그것은 또한 그것을위한 예술의 용어라고 생각합니다 :-)
Steve Jessop 09.06.09

4

제가 생각할 수있는 한 가지 예는 테이블, 손전등 및 배터리 시나리오입니다. 손전등과 한 쌍의 배터리가 테이블 위에 놓여 있다고 상상해보십시오. 다른 사람이 손전등을 가지고있는 동안이 테이블로 걸어가 배터리를 움켜 잡으면 두 사람은 누가 먼저 물건을 테이블에 올려 놓을 지 기다리는 동안 서로 어색하게 서로를 응시해야합니다. 이것은 교착 상태의 예입니다. 당신과 그 사람은 자원을 기다리고 있지만 아무도 그들의 자원을 포기하지 않습니다.

마찬가지로 프로그램에서 교착 상태는 둘 이상의 스레드 (사용자와 다른 사람)가 둘 이상의 잠금 (손전등 및 배터리)이 해제되기를 기다리고 있고 프로그램의 상황이 잠금이 해제되지 않는 것과 같은 경우에 발생합니다. 둘 다 퍼즐 한 조각을 가지고 있습니다).

Java를 알고 있다면 다음과 같이이 문제를 나타낼 수 있습니다.

import java.util.concurrent.locks.*;

public class Deadlock1 {

    public static class Table {

        private static Lock Flashlight = new ReentrantLock();
        private static Lock Batteries = new ReentrantLock();        

        public static void giveFlashLightAndBatteries() {
            try {
                Flashlight.lock();
                Batteries.lock();
                System.out.println("Lights on");
            } finally {
                Batteries.unlock();
                Flashlight.unlock();
            }
        }

        public static void giveBatteriesAndFlashLight() {
            try {
                Batteries.lock();
                Flashlight.lock();
                System.out.println("Lights on");
            } finally {
                Flashlight.unlock();
                Batteries.unlock();
            }
        }
    }

    public static void main(String[] args) {
        // This thread represents person one
        new Thread(new Runnable() {
            public void run() { Table.giveFlashLightAndBatteries(); }
        }).start();

        // This thread represents person two
        new Thread(new Runnable() {
            public void run() { Table.giveBatteriesAndFlashLight(); }
        }).start();
    }
}

이 예제를 실행하면 가끔 일이 제대로 작동한다는 것을 알 수 있습니다. 그러나 때로는 프로그램이 아무것도 인쇄하지 않을 수도 있습니다. 한 사람은 배터리를 가지고 있고 다른 사람은 손전등을 가지고있어 교착 상태를 일으키는 손전등을 켜지 못하게하기 때문입니다.

이 예제는 Java 자습서에서 제공하는 예제와 유사합니다. http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

또 다른 예는 루프 예입니다.

public class Deadlock2 {

    public static class Loop {
        private static boolean done = false;

        public static synchronized void startLoop() throws InterruptedException {
            while(!done) {
                Thread.sleep(1000);
                System.out.println("Not done");
            }
        }

        public static synchronized void stopLoop() {
            done = true;
        }

    }

    public static void main(String[] args) {
        // This thread starts the loop
        new Thread(new Runnable() {
            public void run() {
                try {
                    Loop.startLoop();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // This thread stops the loop
        new Thread(new Runnable() {
            public void run() {
                Loop.stopLoop();
            }
        }).start();
    }
}

이 예제는 '완료되지 않음'을 반복해서 인쇄하거나 '완료되지 않음'을 전혀 인쇄 할 수 없습니다. 첫 번째는 첫 번째 스레드가 클래스 잠금을 획득하고 두 번째 스레드가 'stopLoop'에 액세스하는 것을 방지하기 위해 잠금을 해제하지 않기 때문에 발생합니다. 그리고 두 번째 스레드가 첫 번째 스레드보다 먼저 시작되어 첫 번째 스레드가 실행되기 전에 'done'변수가 true가 되었기 때문에 가장 최근에 발생합니다.


4
public class DeadLock {
    public static void main(String[] args) throws InterruptedException {
        Thread mainThread = Thread.currentThread();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mainThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread1.start();
        thread1.join();
    }
}

3

4 개의 교착 상태 요구 사항을 도면 (특히 순환 대기)으로 쉽게 설명 할 수 있기 때문에 Dining Philosophers 문제가 교착 상태를 보여주는 더 간단한 예 중 하나라고 생각합니다.

나는 현실 세계의 예가 초보자에게 훨씬 더 혼란 스럽다고 생각하지만, 지금 당장은 좋은 현실 세계 시나리오를 생각할 수 없습니다 (실제 동시성에 상대적으로 경험이 없습니다).


3

저는 최근에 부부 간의 싸움이 교착 상태 일 뿐이라는 것을 깨달았습니다. 일반적으로 프로세스 중 하나가 충돌을 해결해야하는 경우, 물론 우선 순위가 낮은 것입니다 (Boy;)).

비유는 다음과 같습니다 ...

Process1 : Girl (G) Process2 : Boy (B)
Resource1 : 죄송합니다 Resource2 : 자신의 실수를 받아들이 기

필요한 조건 :
1. 상호 배제 : 한 번에 G 또는 B 중 하나만 미안하다고 말하거나 자신의 실수를 받아 들일 수 있습니다.
2. 보류 및 대기 : 한 번에 하나는 미안함을 잡고 다른 하나는 자신의 실수를 받아들이고, 하나는 자신의 실수를 받아들이고 미안을 풀어주기를 기다리고 있으며, 다른 하나는 자신의 실수를 받아들이는 것을 풀기 위해 미안을 기다리고 있습니다.
3. 선점 없음 : 신조차도 B 나 G가 미안하거나 자신의 실수를 받아들이도록 강요 할 수 없습니다. 그리고 자발적으로? 장난 해 ??
4. 순환 대기 : 다시, 미안함을 들고있는 사람은 다른 사람이 자신의 실수를 받아들이기를 기다립니다. 그래서 그것은 원형입니다.

따라서 이러한 모든 조건이 동시에 적용될 때 교착 상태가 발생하며 항상 부부 싸움에서 그렇습니다.)

출처 : http://www.quora.com/Saurabh-Pandey-3/Posts/Never-ending-couple-fights-a-deadlock


3

두 개의 다른 리소스와 두 개의 스레드가 서로 리소스를 해제하기를 기다리는 간단한 교착 상태 예제입니다. examples.oreilly.com/jenut/Deadlock.java 에서 직접

 public class Deadlock {
  public static void main(String[] args) {
    // These are the two resource objects we'll try to get locks for
    final Object resource1 = "resource1";
    final Object resource2 = "resource2";
    // Here's the first thread.  It tries to lock resource1 then resource2
    Thread t1 = new Thread() {
      public void run() {
        // Lock resource 1
        synchronized(resource1) {
          System.out.println("Thread 1: locked resource 1");

          // Pause for a bit, simulating some file I/O or something.  
          // Basically, we just want to give the other thread a chance to
          // run.  Threads and deadlock are asynchronous things, but we're
          // trying to force deadlock to happen here...
          try { Thread.sleep(50); } catch (InterruptedException e) {}

          // Now wait 'till we can get a lock on resource 2
          synchronized(resource2) {
            System.out.println("Thread 1: locked resource 2");
          }
        }
      }
    };

    // Here's the second thread.  It tries to lock resource2 then resource1
    Thread t2 = new Thread() {
      public void run() {
        // This thread locks resource 2 right away
        synchronized(resource2) {
          System.out.println("Thread 2: locked resource 2");

          // Then it pauses, for the same reason as the first thread does
          try { Thread.sleep(50); } catch (InterruptedException e) {}

          // Then it tries to lock resource1.  But wait!  Thread 1 locked
          // resource1, and won't release it 'till it gets a lock on
          // resource2.  This thread holds the lock on resource2, and won't
          // release it 'till it gets resource1.  We're at an impasse. Neither
          // thread can run, and the program freezes up.
          synchronized(resource1) {
            System.out.println("Thread 2: locked resource 1");
          }
        }
      }
    };

    // Start the two threads. If all goes as planned, deadlock will occur, 
    // and the program will never exit.
    t1.start(); 
    t2.start();
  }
}

If all goes as planned, deadlock will occur, and the program will never exit.이 예제를 guarantee교착 상태로 만들 수 있습니까 ?
Erran Morad 2014 년

이것은 Kyle이 게시 한 것과 동일한 코드입니다. 다른 답변 3 년 후에 중복 답변을 추가하는 이유는 무엇입니까? (이유는 나중에 3 년, 그 위에 언급합니까?)
사이먼 포스 버그에게

2

A는 경우 교착 상황에서 발생할 수 있습니다 Girl1꼬시 원하는되는 Guy2다른 의해 체포되고, Girl2Girl2꼬시 원해요 Guy1에 의해 체포된다 Girl1. 두 소녀가 서로를 버리기를 기다리고 있기 때문에 그 상태를 교착 상태라고합니다.

class OuchTheGirls
{
    public static void main(String[] args)
    {
        final String resource1 = "Guy1";
        final String resource2 = "Guy2";

        // Girl1 tries to lock resource1 then resource2
        Thread Girl1 = new Thread(() ->
                                  {
                                      synchronized (resource1)
                                      {
                                          System.out.println("Thread 1: locked Guy1");

                                          try { Thread.sleep(100);} catch (Exception e) {}

                                          synchronized (resource2)
                                          {
                                              System.out.println("Thread 1: locked Guy2");
                                          }
                                      }
                                  });

        // Girl2 tries to lock Guy2 then Guy1
        Thread Girl2 = new Thread(() ->
                                  {
                                      synchronized (resource2)
                                      {
                                          System.out.println("Thread 2: locked Guy2");

                                          try { Thread.sleep(100);} catch (Exception e) {}

                                          synchronized (resource1)
                                          {
                                              System.out.println("Thread 2: locked Guy1");
                                          }
                                      }
                                  });


        Girl1.start();
        Girl2.start();
    }
}


1

학생들에게 개념을 소개 할 때 교착 상태가 발생할 수있는 단순한 시나리오로 이동하십시오. 여기에는 최소 2 개의 스레드와 최소 2 개의 리소스가 포함됩니다 (제 생각에). 목표는 첫 번째 스레드가 리소스 1에 대한 잠금을 갖고 있고 리소스 2에 대한 잠금이 해제되기를 기다리는 동안 동시에 스레드 2가 리소스 2에 대한 잠금을 보유하고 대기중인 시나리오를 엔지니어링하는 것입니다. 해제 할 리소스 1에 대한 잠금.

기본 리소스가 무엇인지는 실제로 중요하지 않습니다. 단순화를 위해 두 스레드가 모두 쓸 수있는 파일 쌍으로 만들 수 있습니다.

편집 : 이것은 보유 된 잠금 이외의 프로세스 간 통신이 없다고 가정합니다.


1

식당 철학자들의 문제를 읽을 때 약간 이해하기 어렵다는 것을 알았습니다. IMHO 교착 상태는 실제로 자원 할당과 관련이 있습니다. 2 명의 간호사가 작업을 완료하기 위해 3 개의 장비를 위해 싸워야하는 더 간단한 예를 공유하고 싶습니다. Java로 작성되었지만. 교착 상태가 발생하는 방식을 시뮬레이션하기 위해 간단한 lock () 메서드가 생성되므로 다른 프로그래밍 언어에도 적용 할 수 있습니다. http://www.justexample.com/wp/example-of-deadlock/


1

https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html의 간단한 예

public class Deadlock {

public static void printMessage(String message) {

    System.out.println(String.format("%s %s ", Thread.currentThread().getName(), message));

}

private static class Friend {

    private String name;

    public Friend(String name) {
        this.name = name;
    }

    public void bow(Friend friend) {

        printMessage("Acquiring lock on " + this.name);

        synchronized(this) {
            printMessage("Acquired lock on " + this.name);
            printMessage(name + " bows " + friend.name);
            friend.bowBack(this);
        }

    }

    public void bowBack(Friend friend) {

        printMessage("Acquiring lock on " + this.name);

        synchronized (this) {
            printMessage("Acquired lock on " + this.name);
            printMessage(friend.name + " bows back");
        }

    }

}

public static void main(String[] args) throws InterruptedException {

    Friend one = new Friend("one");
    Friend two = new Friend("two");

    new Thread(new Runnable() {
        @Override
        public void run() {
            one.bow(two);
        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            two.bow(one);
        }
    }).start();
}

}

산출:

Thread-0 Acquiring lock on one 
Thread-1 Acquiring lock on two 
Thread-0 Acquired lock on one 
Thread-1 Acquired lock on two 
Thread-1 two bows one 
Thread-0 one bows two 
Thread-1 Acquiring lock on one 
Thread-0 Acquiring lock on two 

스레드 덤프 :

2016-03-14 12:20:09
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.74-b02 mixed mode):

"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x00007f472400a000 nid=0x3783 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f472420d800 nid=0x37a3 waiting for monitor entry [0x00007f46e89a5000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$2.run(ThreadJoin.java:141)
    at java.lang.Thread.run(Thread.java:745)

"Thread-0" #11 prio=5 os_prio=0 tid=0x00007f472420b800 nid=0x37a2 waiting for monitor entry [0x00007f46e8aa6000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$1.run(ThreadJoin.java:134)
    at java.lang.Thread.run(Thread.java:745)

"Monitor Ctrl-Break" #10 daemon prio=5 os_prio=0 tid=0x00007f4724211000 nid=0x37a1 runnable [0x00007f46e8def000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:170)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    - locked <0x000000076d20afb8> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    - locked <0x000000076d20afb8> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    at com.intellij.rt.execution.application.AppMain$1.run(AppMain.java:93)
    at java.lang.Thread.run(Thread.java:745)

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007f47240c9800 nid=0x3794 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007f47240c6800 nid=0x3793 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f47240c4000 nid=0x3792 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f47240c2800 nid=0x3791 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f47240bf800 nid=0x3790 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f47240be000 nid=0x378f waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f472408c000 nid=0x378e in Object.wait() [0x00007f46e98c5000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076cf88ee0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x000000076cf88ee0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f4724087800 nid=0x378d in Object.wait() [0x00007f46e99c6000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076cf86b50> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x000000076cf86b50> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=0 tid=0x00007f4724080000 nid=0x378c runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f472401f000 nid=0x3784 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f4724021000 nid=0x3785 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f4724022800 nid=0x3786 runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f4724024800 nid=0x3787 runnable 

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007f4724026000 nid=0x3788 runnable 

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007f4724028000 nid=0x3789 runnable 

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007f4724029800 nid=0x378a runnable 

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007f472402b800 nid=0x378b runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f47240cc800 nid=0x3795 waiting on condition 

JNI global references: 16


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f46dc003f08 (object 0x000000076d0583a0, a com.anantha.algorithms.ThreadJoin$Friend),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f46dc006008 (object 0x000000076d0583e0, a com.anantha.algorithms.ThreadJoin$Friend),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$2.run(ThreadJoin.java:141)
    at java.lang.Thread.run(Thread.java:745)
"Thread-0":
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$1.run(ThreadJoin.java:134)
    at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

Heap
 PSYoungGen      total 74752K, used 9032K [0x000000076cf80000, 0x0000000772280000, 0x00000007c0000000)
  eden space 64512K, 14% used [0x000000076cf80000,0x000000076d8520e8,0x0000000770e80000)
  from space 10240K, 0% used [0x0000000771880000,0x0000000771880000,0x0000000772280000)
  to   space 10240K, 0% used [0x0000000770e80000,0x0000000770e80000,0x0000000771880000)
 ParOldGen       total 171008K, used 0K [0x00000006c6e00000, 0x00000006d1500000, 0x000000076cf80000)
  object space 171008K, 0% used [0x00000006c6e00000,0x00000006c6e00000,0x00000006d1500000)
 Metaspace       used 3183K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 352K, capacity 388K, committed 512K, reserved 1048576K

1

다음은 Java의 간단한 교착 상태입니다. 교착 상태를 증명하려면 두 가지 리소스가 필요합니다. 아래 예에서 한 리소스는 동기화 메서드를 통해 클래스 잠금이고 다른 리소스는 정수 'i'입니다.

public class DeadLock {

    static int i;
    static int k;

    public static synchronized void m1(){
        System.out.println(Thread.currentThread().getName()+" executing m1. Value of i="+i);

        if(k>0){i++;}

        while(i==0){
            System.out.println(Thread.currentThread().getName()+" waiting in m1 for i to be > 0. Value of i="+i);
            try { Thread.sleep(10000);} catch (InterruptedException e) { e.printStackTrace(); }
        }
    }

    public static void main(String[] args) {

        Thread t1 = new Thread("t1") {
            public void run() {
                m1();
            }
        };

        Thread t2 = new Thread("t2") {
            public void run() {
                try { Thread.sleep(100);} catch (InterruptedException e) { e.printStackTrace(); }
                k++;
                m1();
            }
        };

        t1.start();
        t2.start();
    }
}

1
public class DeadLock {

    public static void main(String[] args) {
        Object resource1 = new Object();
        Object resource2 = new Object();
        SharedObject s = new SharedObject(resource1, resource2);
        TestThread11 t1 = new TestThread11(s);
        TestThread22 t2 = new TestThread22(s);
        t1.start();
        t2.start();
    }

}

class SharedObject {
    Object o1, o2;
    SharedObject(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    void m1() {
        synchronized(o1) {
            System.out.println("locked on o1 from m1()");
            synchronized(o2) { 
                System.out.println("locked on o2 from m1()");
            }
        }
    }
    void m2() {
        synchronized(o2) {
            System.out.println("locked on o2 from m2()");
            synchronized(o1) { 
                System.out.println("locked on o1 from m2()");
            }
        }
    }
}

class TestThread11 extends Thread {
    SharedObject s;
    TestThread11(SharedObject s) {
        this.s = s;
    }
    public void run() {
        s.m1();
    }
}

class TestThread22 extends Thread {
    SharedObject s;
    TestThread22(SharedObject s) {
        this.s = s;
    }
    public void run() {
        s.m2();
    }
}

1
답변을 설명하는 텍스트를 추가해 주시겠습니까?
Kmeixner

1

다음은 C #의 간단한 교착 상태입니다.

void UpdateLabel(string text) {
   lock(this) {
      if(MyLabel.InvokeNeeded) {
        IAsyncResult res =  MyLable.BeginInvoke(delegate() {
             MyLable.Text = text;
            });
         MyLabel.EndInvoke(res);
        } else {
             MyLable.Text = text;
        }
    }
}

어느 날 GUI 스레드에서 이것을 호출하고 다른 스레드도이를 호출하면 교착 상태가 될 수 있습니다. 다른 스레드는 EndInvoke에 도달하고 잠금을 유지하는 동안 GUI 스레드가 대리자를 실행하기를 기다립니다. GUI 스레드는 다른 스레드가 해제하기를 기다리는 동일한 잠금에서 차단됩니다. 이는 GUI 스레드가 다른 스레드가 기다리고있는 델리게이트를 실행할 수 없기 때문입니다. (물론 여기에서 잠금이 꼭 필요한 것은 아닙니다. EndInvoke도 마찬가지지만 약간 더 복잡한 시나리오에서는 다른 이유로 호출자가 잠금을 획득하여 동일한 교착 상태가 발생할 수 있습니다.)


0
package test.concurrent;
public class DeadLockTest {
   private static long sleepMillis;
   private final Object lock1 = new Object();
   private final Object lock2 = new Object();

   public static void main(String[] args) {
       sleepMillis = Long.parseLong(args[0]);
       DeadLockTest test = new DeadLockTest();
       test.doTest();
   }

   private void doTest() {
       Thread t1 = new Thread(new Runnable() {
           public void run() {
               lock12();
           }
       });
       Thread t2 = new Thread(new Runnable() {
           public void run() {
               lock21();
           }
       });
       t1.start();
       t2.start();
   }

   private void lock12() {
       synchronized (lock1) {
           sleep();
           synchronized (lock2) {
               sleep();
           }
       }
   }

   private void lock21() {
       synchronized (lock2) {
           sleep();
           synchronized (lock1) {
               sleep();
           }
       }
   }

   private void sleep() {
       try {
           Thread.sleep(sleepMillis);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
To run the deadlock test with sleep time 1 millisecond:
java -cp . test.concurrent.DeadLockTest 1

0
public class DeadlockProg {

    /**
     * @Gowtham Chitimi Reddy IIT(BHU);
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        final Object ob1 = new Object();
        final Object ob2 = new Object();
        Thread t1 = new Thread(){
            public void run(){
                synchronized(ob1){
                    try{
                        Thread.sleep(100);
                    }
                    catch(InterruptedException e){
                        System.out.println("Error catched");
                    }
                    synchronized(ob2){

                    }
                }

            }
        };
        Thread t2 = new Thread(){
            public void run(){
                synchronized(ob2){
                    try{
                        Thread.sleep(100);
                    }
                    catch(InterruptedException e){
                        System.out.println("Error catched");
                    }
                    synchronized(ob1){                      
                    }
                }               
            }
        };
        t1.start();
        t2.start();
    }

}

0
package ForkBlur;

public class DeadLockTest {
  public static void main(String args[]) {

    final DeadLockTest t1 = new DeadLockTest();
    final DeadLockTest t2 = new DeadLockTest();

    Runnable r1 = new Runnable() {

        @Override
        public void run() {
            try {

                synchronized (t1) {
                    System.out
                            .println("r1 has locked t1, now going to sleep");
                    Thread.sleep(100);
                    System.out
                            .println("r1 has awake , now going to aquire lock for t2");
                    synchronized (t2) {
                        Thread.sleep(100);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };

    Runnable r2 = new Runnable() {

        @Override
        public void run() {
            try {

                synchronized (t2) {
                    System.out
                            .println("r2 has aquire the lock of t2 now going to sleep");
                    Thread.sleep(100);
                    System.out
                            .println("r2 is awake , now going to aquire the lock from t1");
                    synchronized (t1) {
                        Thread.sleep(100);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };

    new Thread(r1).start();
    new Thread(r2).start();
  }
}

0

초간단 작업 데드락 예제를 만들었습니다.

package com.thread.deadlock;

public class ThreadDeadLockClient {

    public static void main(String[] args) {
        ThreadDeadLockObject1 threadDeadLockA = new ThreadDeadLockObject1("threadDeadLockA");
        ThreadDeadLockObject2 threadDeadLockB = new ThreadDeadLockObject2("threadDeadLockB");

        new Thread(new Runnable() {

            @Override
            public void run() {
                threadDeadLockA.methodA(threadDeadLockB);

            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                threadDeadLockB.methodB(threadDeadLockA);

            }
        }).start();
    }
}

package com.thread.deadlock;

public class ThreadDeadLockObject1 {

    private String name;

    ThreadDeadLockObject1(String name){
        this.name = name;
    }

    public  synchronized void methodA(ThreadDeadLockObject2 threadDeadLockObject2) {
        System.out.println("In MethodA "+" Current Object--> "+this.getName()+" Object passed as parameter--> "+threadDeadLockObject2.getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        threadDeadLockObject2.methodB(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }   
}

package com.thread.deadlock;

public class ThreadDeadLockObject2 {

    private String name;

    ThreadDeadLockObject2(String name){
        this.name = name;
    }

    public  synchronized void methodB(ThreadDeadLockObject1 threadDeadLockObject1) {
        System.out.println("In MethodB "+" Current Object--> "+this.getName()+" Object passed as parameter--> "+threadDeadLockObject1.getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        threadDeadLockObject1.methodA(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

위의 예에서 2 개의 스레드는 서로 다른 두 개체의 동기화 된 메서드를 실행하고 있습니다. 동기화 된 methodA는 개체 threadDeadLockA에 의해 호출되고 동기화 된 methodB는 개체 threadDeadLockB에 의해 호출됩니다. methodA에서는 threadDeadLockB의 참조가 전달되고 methodB에서는 threadDeadLockA의 참조가 전달됩니다. 이제 각 스레드는 다른 객체에 대한 잠금을 시도합니다. methodA에서 threadDeadLockA에 잠금을 보유하고있는 스레드는 threadDeadLockB 객체에 대한 잠금을 얻으려고 시도하고 있으며 유사하게 methodB에서는 threadDeadLockB에 잠금을 보유하고있는 스레드가 threadDeadLockA에 대한 잠금을 얻으려고합니다. 따라서 두 스레드 모두 교착 상태를 생성하면서 영원히 기다립니다.


0

스레드 가 2 개 이상인 예제를 사용하여 더 명확하게 설명하겠습니다 .

각각 잠금 L1, L2, ..., Ln을 보유하는 n 개의 스레드가 있다고 가정 해 보겠습니다. 이제 스레드 1부터 시작하여 각 스레드가 인접 스레드의 잠금을 획득하려고한다고 가정 해 보겠습니다. 따라서 스레드 1은 L2 획득을 시도하기 위해 차단되고 (L2는 스레드 2가 소유하므로) 스레드 2는 L3에 대해 차단됩니다. 스레드 n은 L1에 대해 차단됩니다. 스레드를 실행할 수 없으므로 이제 교착 상태입니다.

class ImportantWork{
   synchronized void callAnother(){     
   }
   synchronized void call(ImportantWork work) throws InterruptedException{
     Thread.sleep(100);
     work.callAnother();
   }
}
class Task implements Runnable{
  ImportantWork myWork, otherWork;
  public void run(){
    try {
      myWork.call(otherWork);
    } catch (InterruptedException e) {      
    }
  }
}
class DeadlockTest{
  public static void main(String args[]){
    ImportantWork work1=new ImportantWork();
    ImportantWork work2=new ImportantWork();
    ImportantWork work3=new ImportantWork();
    Task task1=new Task(); 
    task1.myWork=work1;
    task1.otherWork=work2;

    Task task2=new Task(); 
    task2.myWork=work2;
    task2.otherWork=work3;

    Task task3=new Task(); 
    task3.myWork=work3;
    task3.otherWork=work1;

    new Thread(task1).start();
    new Thread(task2).start();
    new Thread(task3).start();
  }
}

위의 예에서 Runnabletask1, task2 및 task3을 보유하는 세 개의 스레드가 있음을 알 수 있습니다 . 문 앞에 sleep(100)스레드가 call()메서드에 들어갈 때 세 개의 작업 개체의 잠금을 획득합니다 (가 존재하기 때문에 synchronized). 그러나 callAnother()이웃 스레드의 개체에 대해 시도하자마자 차단되어 해당 개체의 잠금이 이미 사용 되었기 때문에 교착 상태가 발생합니다.


0
CountDownLatch countDownLatch = new CountDownLatch(1);
ExecutorService executorService = ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> {
    Future<?> future = executorService.submit(() -> {
        System.out.println("generated task");
    });
    countDownLatch.countDown();
    try {
        future.get();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
         e.printStackTrace();
    }
});


countDownLatch.await();
executorService.shutdown();

0

단일 스레드로 교착 상태에 빠지는 교활한 방법은 동일한 (비재 귀적) 뮤텍스를 두 번 잠그는 것입니다. 이것은 당신이 찾고 있던 간단한 예가 아닐 수도 있지만 이미 그러한 경우를 만났습니다.

#include <mutex>
#include <iostream>

int main()
{
  std::mutex m;
  m.lock();
  m.lock();
  std::cout << "Expect never to get here because of a deadlock!";
}

0

다음은 많은 시간을 보낸 후의 교착 상태에 대한 자세한 예입니다 . 도움이되기를 바랍니다 :)

package deadlock;

public class DeadlockApp {

    String s1 = "hello";
    String s2 = "world";

    Thread th1 = new Thread() {
        public void run() {
            System.out.println("Thread th1 has started");
            synchronized (s1) { //A lock is created internally (holds access of s1), lock will be released or unlocked for s1, only when it exits the block Line #23
                System.out.println("Executing first synchronized block of th1!");
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException ex) {
                    System.out.println("Exception is caught in th1");
                }
                System.out.println("Waiting for the lock to be released from parrallel thread th1");
                synchronized (s2) { //As another has runned parallely Line #32, lock has been created for s2
                    System.out.println(s1 + s2);
                }

            }
            System.out.println("Thread th1 has executed");
        }
    };


    Thread th2 = new Thread() {
        public void run() {
            System.out.println("Thread th2 has started");
            synchronized (s2) { //A lock is created internally (holds access of s2), lock will be released or unlocked for s2, only when it exits the block Line #44
                System.out.println("Executing first synchronized block of th2!");
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException ex) {
                    System.out.println("Exception is caught in th2");
                }
                System.out.println("Waiting for the lock to be released from parrallel thread th2");
                synchronized (s1) { //As another has runned parallely Line #11, lock has been created for s1
                    System.out.println(s1 + s2);
                }

            }
            System.out.println("Thread th2 has executed");
        }
    };

    public static void main(String[] args) {
        DeadlockApp deadLock = new DeadlockApp();
        deadLock.th1.start();
        deadLock.th2.start();
        //Line #51 and #52 runs parallely on executing the program, a lock is created inside synchronized method
        //A lock is nothing but, something like a blocker or wall, which holds access of the variable from being used by others.
        //Locked object is accessible, only when it is unlocked (i.e exiting  the synchronized block)
        //Lock cannot be created for primitive types (ex: int, float, double)
        //Dont forget to add thread.sleep(time) because if not added, then object access will not be at same time for both threads to create Deadlock (not actual runtime with lots of threads) 
        //This is a simple program, so we added sleep90 to create Deadlock, it will execute successfully, if it is removed. 
    }

    //Happy coding -- Parthasarathy S
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.