Java:マルチスレッドデッドロック


デッドロック:2つ以上のプロセスが実行中に資源を争うことによって互いに待つ現象であり、外力の作用がなければ推進できない.
デッドロックの原因:
    1.システムのリソースが不足しているからです.
    2.プロセスの実行が進む順序が適切ではありません.    
    3.資源の分配が適切でない.
デッドロックが発生する条件:
  • 反発条件:反発とは、プロセスがある時間内にリソースを独占することである.
  • 要求と保持条件:1つのプロセスが要求リソースによってブロックされた場合、取得したリソースは保持されません.
  • 条件を剥奪しない:プロセスはすでに資源を獲得し、最後の使用が終わる前に、強制的に剥奪することはできない.
  • サイクル待機条件:いくつかのプロセスの間にヘッドとテールが接続されたサイクル待機リソース関係が形成される.

  • 簡単に言えば、デッドロックは、マルチスレッドがオブジェクトにアクセスする際に、Aスレッドがオブジェクトobject 1を占有し、オブジェクトobject 2を占有しようとするが、このときのobject 2オブジェクトはすでにBスレッドに占有されており、Bスレッドがobject 2を占有しようとするからである.2つのスレッドは同時に相手が望んでいるオブジェクトを占有するが,自分が占有しているオブジェクトを解放せず,2つのスレッドが互いに待機し,混雑して実行できない.
        
    public class LockDemo implements Runnable
    {
        private static Object object1 = new Object();
        
        private static Object object2 = new Object();
        
        private int flag = 0;
        
        public static void main(String[] args)
        {
            LockDemo run0 = new LockDemo();
            LockDemo run1 = new LockDemo();
            run0.flag = 1;
            run1.flag = 2;
            Thread thread1 = new Thread(run0);
            Thread thread2 = new Thread(run1);
            thread1.start();
            thread2.start();
        }
        
        @Override
        public void run()
        {
            System.out.println(flag);
            if (flag == 1)
            {
                synchronized (object1)
                {
                    System.out.println("   : " + flag + "  obj1,  0.5    obj2 !");
                    try
                    {
                        Thread.sleep(500);
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                    synchronized (object2)
                    {
                        System.out.println("   : " + flag + "   object2");
                    }
                }
            }
            if (flag == 2)
            {
                synchronized (object2)
                {
                    System.out.println("   : " + flag + "  obj2,  0.5    obj1 !");
                    try
                    {
                        Thread.sleep(500);
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                    synchronized (object1)
                    {
                        System.out.println("   : " + flag + "  object1");
                    }
                }
            }
            
        }
        
    }

    実行結果
    1
    2
       : 2  obj2,  0.5    obj1 !
       : 1  obj1,  0.5    obj2 !

    実行の結果,各スレッドは実行されていないことが分かった.
    System.out.println("   : " + flag + "  object");

    スレッド1がコードを実行するときにobject 1をロックしてobject 2にアクセスするため、このときのobject 2はすでにスレッド2にロックされており、スレッド1とスレッド2はそれぞれobject 1とobject 2を占有し、また相手の占有するオブジェクトにアクセスしようとするが、明らかに不可能である.2人の子供がおもちゃを交換するように、1人の子供は言います:あなたは先におもちゃを私にあげて、私は更におもちゃをあなたにあげて、もう1人の子供は言います:だめです、あなたは先にあなたのおもちゃを私にあげて、私は更にあなたにあげます.結局二人の子供は誰にもあげたくなくて、自然にそこに硬直しています.
    コードでobjectオブジェクトを修飾するときにstaticキーワードを使用しますが、staticキーワードを使用しない実行結果はどうなりますか?
    1
       : 1  obj1,  0.5    obj2 !
    2
       : 2  obj2,  0.5    obj1 !
       : 2  object1
       : 1   object2

    デッドロックが発生していないのが見えますが、なぜですか?staticキーワードを使用する場合、2つのobjectは共通であり、キーワードを使用しない場合、2つのobjectはスレッド自身が2つの独立したオブジェクトを使用しているからです.同じように、staticの重要な修飾を使ったobjectの対象は、幼稚園にある2つのおもちゃのように、誰でも遊ぶことができますが、子供一人一人が、同時に1つしか持っていません.一人の子供がもう一人の子供のおもちゃを遊びたいなら、二人で交換しなければなりません.staticキーワードで修飾しないobjectオブジェクトは、子供一人一人が自分でおもちゃを持って遊びに来るようなもので、共有ではありません.私が遊びたいものは何でも遊びます.