簡単なデッドロックの例


92

初心者にスレッドデッドロックについて説明したいと思います。私は過去に多くのデッドロックの例を見てきました。コードを使用したり、イラストを使用したりします(有名な4台の車など)。The Dining Philosophersのような、簡単に行き詰まりがちな古典的な問題もありますが、本当の初心者には完全に理解するには複雑すぎる場合があります。

デッドロックとは何かを説明する最も簡単なコード例を探しています。例は次のようにする必要があります。

  1. ある意味のある「実際の」プログラミングシナリオに関連する
  2. 非常に短く、シンプルでわかりやすい

何がお勧めですか?


有名な4台の車を使ってみませんか。
vehomzzz 2009

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)を同時に実行しようとする2つのスレッドがある場合、逆の順序でリソースを取得しようとするため、デッドロックが発生します。

このコードは、デッドロックの解決策を見るためにも最適です。お役に立てれば!


1
あなたや他の誰かがこの問題の解決策を提供できれば完璧です。
ジャッキー、2013年

2
この問題の@Jackyソリューションは、ここでウィル・アルトゥングによって投稿されていますstackoverflow.com/questions/13326861/avoid-deadlock-example/...
ピョートルChojnackiを

2
私はあなたの構文に混乱しています。sync()メソッドとは何ですか?sync(from); ... release(from);なら理解できます。synchronized(from){...}に置き換えられました
Ellen Spertus 2014年

1
@espertus syncは次のようになりますsync(Account & a) { a.mutex.lock(); }
vladon 2016

1
javaworld.com/article/2075692/java-concurrency/…(Brian Goetz)がこの問題の解決策を説明しています。
lingareddyk 2018

59

自然にデッドロックを説明させて、

Deadlock:Frog vs. Snake

「彼らが別々の道を進むのを見たかったのですが、私は疲れ果てていました」 「カエルはいつも ヘビ 引き離そうとしましたが、ヘビは手放せませんでした」

ここに画像の説明を入力してください


59
かわいいですが、プログラミングコンテキストでデッドロックがどのように発生するかは説明していません。
2009

じゃあ、少なくともあなたは反対票を正当化しました。とにかく、「4車」の例に似ています。かわいいデッドロックがどのように見えるかの表現。
Nick Dandoulakis

@Nick Dandoulakis:優れた絵画的プレゼンテーション。写真はデッドロックの概念を説明しています
Rasmi Ranjan Nayak

@NickDandoulakis-良い写真の例ではありません。ここでは単純なコードが役に立ちます。
Erran Morad 14年

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、2012

このコードは2、3冊の本で公開されているようです... stackoverflow.com/a/11338853/112705
Dan J

15

method1()とmethod2()の両方が2つ以上のスレッドによって呼び出される場合、スレッド1がmethod1()の実行中にStringオブジェクトのロックを取得し、スレッド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

私が遭遇した単純なデッドロックの例の1つ。

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から継承されるのでしょうか。それは必要ありません。
チャーミン2013

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つのスレッドが2つの異なるリソースを取得する必要があり、異なる順序で取得する必要がある場合は、デッドロックが発生する可能性があります。


2
ここで別の回答からの情報を複製することのポイントは本当にわかりません。この回答を改善できると思うなら、自分で自由に編集できると思います。
djna 2009

この状況を「ロック反転」と呼んでいると思います。私はあることそれを呼び出すが、私はそれはまた、そのための技術用語だと思う:-)ので、まあ、私は、それは反転をロックと呼ばれています知っている
スティーブ・ジェソップ

4

私が考えることができる1つの例は、テーブル、懐中電灯、およびバッテリーのシナリオです。テーブルの上に置かれた懐中電灯とバッテリーのペアを想像してみてください。他の人が懐中電灯を持っているときにこのテーブルに歩いてバッテリーをつかむと、どちらが最初にアイテムをテーブルに戻すかを待つ間、両方がぎこちなく凝視しなければなりません。これはデッドロックの例です。あなたとその人はリソースを待っていますが、リソースを放棄している人はいません。

同様に、プログラムでは、2つ以上のスレッド(あなたと他の人)が2つ以上のロック(懐中電灯とバッテリー)が解放されるのを待っているときにデッドロックが発生し、プログラムの状況ではロックが解放されない(両方ともパズルのピースが1つあります)。

あなたが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();
    }
}

この例では、「未完了」を繰り返し印刷することも、「未完了」をまったく印刷しないこともできます。最初のスレッドは、最初のスレッドがクラスロックを取得し、それを解放しないため、2番目のスレッドによる「stopLoop」へのアクセスを妨げます。そして、最新のイベントが発生するのは、最初のスレッドの前に2番目のスレッドが開始され、最初のスレッドが実行される前に「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つのデッドロック要件は図面(特に循環待機)で簡単に説明できるため、私はダイニングフィロソファーズの問題をデッドロックを示す最も単純な例の1つと考えています。

現実世界の例は、初心者にとってははるかに混乱していると思いますが、現時点では頭に浮かぶ適切な現実世界のシナリオを考えることはできません(現実世界の並行性には比較的慣れていません)。


3

私は最近、カップル間の戦いはデッドロックに過ぎないことに気づきました。通常、プロセスの1つはそれを解決するためにクラッシュする必要がありますが、もちろん優先順位の低いプロセスです(Boy;))。

ここに類推があります...

Process1:Girl(G)Process2:Boy(B)
Resource1:申し訳ありませんResource2:自分の間違いを受け入れる

必要条件:
1.相互排除:申し訳ありませんが、自分の過ちを一度に受け入れることができるのは、GまたはBのいずれか1つだけです。
2.ホールドアンドウェイト:一度に1つは、申し訳ありません、その他自分のミスを受け入れる、もう1つは、自分のミスを受け入れて申し訳ありませんがリリースするのを待っている、もう1つは、申し訳ありませんが自分のミスを受け入れるのをリリースするのを待っている。
3.プリエンプションなし:神でさえ、BまたはGに「申し訳ありません」または「自分の間違いを受け入れる」ことを強制することはできません。そして自発的に?私をからかってるの??
4.循環待ち:繰り返しますが、申し訳ありませんが、他の人が自分の間違いを受け入れるのを待っています。だから円形です。

したがって、これらすべての条件が同時に有効な場合にデッドロックが発生します。これは、カップルの戦いでは常に当てはまります;)

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


3

2つの異なるリソースと2つのスレッドがお互いにリソースを解放するのを待機しているもう1つの簡単なデッドロックの例。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 14年

これはカイルが投稿したコードと同じですが、なぜ3年後に別の回答を追加するのですか?(そして、なぜ3年後、私はそれについてコメントするのですか?)
Simon Forsberg、2015

2

デッドロックは、ときの状況で発生する可能性がありますGirl1と浮気したいされGuy2、別でキャッチされた人、Girl2と、Girl2と浮気したいさ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

生産者・消費者問題、取得するつもりだとして一緒に食事する哲学者の問題とは、おそらく簡単なようです。それを示すいくつかの疑似コードもあります。初心者にとってそれらが複雑すぎる場合は、把握するために一生懸命努力することをお勧めします。


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での簡単なデッドロックは次のとおりです。デッドロックを実証するには2つのリソースが必要です。以下の例では、1つのリソースは(syncメソッドによる)クラスロックで、もう1つのリソースは整数「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 2017

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つのスレッドが2つの異なるオブジェクトの同期されたメソッドを実行しています。同期されたmethodAはオブジェクトthreadDeadLockAによって呼び出され、同期されたmethodBはオブジェクトthreadDeadLockBによって呼び出されます。methodAではthreadDeadLockBの参照が渡され、methodBではthreadDeadLockAの参照が渡されます。これで、各スレッドは別のオブジェクトをロックしようとします。methodAでは、threadDeadLockAでロックを保持しているスレッドがオブジェクトthreadDeadLockBでロックを取得しようとしています。同様に、methodBでは、threadDeadLockBでロックを保持しているスレッドがthreadDeadLockAでロックを取得しようとしています。したがって、両方のスレッドが永久に待機し、デッドロックが発生します。


0

3つ以上のスレッドを持つ例を使用して、より明確に説明します。

それぞれがロック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();
  }
}

上記の例ではRunnable、タスク1、タスク2、タスク3を保持する3つのスレッドがあることがわかります。ステートメントsleep(100)の前に、スレッドはcall()メソッドに入るときに(の存在によりsynchronized)3つの作業オブジェクトのロックを取得します。しかし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

単一のスレッドだけでデッドロックを起こす卑劣な方法は、同じ(再帰的でない)mutexを2回ロックすることです。これはあなたが探していた単純な例ではないかもしれませんが、確かに私はすでにそのようなケースに遭遇しました。

#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.