0

以下のプログラムがデッドロックを保証するかどうか教えてください。以下に詳細を示します。 スレッド: process1 および process2。オブジェクト: スキャナーとプリンター。process1 はスキャナーとプリンターの両方をロックしますが、スキャナーを断念します。process2 はスキャナーをロックしますが、process1 がロックしているため、プリンターを取得できません。おそらく私のスレッドの概念は不明確ですが、どこが間違っているのか教えてください。

class DeadLock extends Thread {

    //creating a scanner object
    private static Object scanner = new Object();

    //creating a printer object
    private static Object printer = new Object();

    //the process name
    private String processName;

    //initializes process2 is not created yet
    private boolean process2IsCreated = false;

    /**
     * the constructor which sets string to process1 or 2
     * @param string
     */
    public DeadLock(String string) {
        // TODO Auto-generated constructor stub
        this.processName  = string;
    }

    /**
     * deadlock() for process1
     */
    public void deadlock1() {

        //process1 locks scanner
        synchronized (scanner) {

            //process1 locks printer, too
            synchronized (printer) {

                //create process2 after process1
                if(process2IsCreated == false && processName.equals("process1")) {
                    new DeadLock("process2").start();
                    process2IsCreated = true;
                }

                try {
                    //process1 is waiting on scanner and releases its monitor. 
                    //After regaining access, process1 tries to acquire scanner
                    //but cannot do so because process2 has locked it already.
                    //. . .too late, process1!
                    scanner.wait();

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }
    }

    /**
     * deadlock() for process2
     */
    public void deadlock2() {

        //process2 locks scanner
        synchronized (scanner) {

            //process2 notifies process1 which is waiting on scanner
            scanner.notify();

            //process2 locks printer, but cannot lock printer because process1 has it
            //. . .too late, process2!
            synchronized (printer) {
            }
        }
    }

    /**
     * both threads are scheduled to execute run()
     */
    public void run() {

        //if process1 then enter deadlock1()
        if(processName.equals ("process1")) deadlock1();

        //if process 2 then enter deadlock2()
        else deadlock2();
    }

    /**
     * the main method which creates thread process1
     * @param a
     */
    public static void main(String a[]) {
        new DeadLock("process1").start();
    }
}
4

5 に答える 5

2

これは私にとってはうまくいっているようです。Intellij のスレッド ダンプは次のとおりです。

ここに画像の説明を入力

于 2013-11-14T23:05:13.590 に答える
0

これを参照してください..ここで2番目のスレッドが開始されています

//create process2 after process1
                if(process2IsCreated == false && processName.equals("process1")) {
                    new DeadLock("process2").start();   <---------------HERE
                    process2IsCreated = true;
                }
于 2013-11-14T23:14:23.330 に答える
0

Java の同期プリミティブを使用してからしばらく経ちましたが、私には次のように見えます。

スレッド 1 はスキャナーをロックします。
スレッド 1 はプリンターをロックします。
スレッド 2 が開始されます。
スレッド 1 は一時的にスキャナを解放し、通知を待ってスリープします。
スレッド 2 はスキャナーをロックします。
スレッド 2 が通知を投稿します。
プリンターで 2 ブロックをスレッド化します。

スレッド 2 はスキャナーを解放しないため、スレッド 1 は起動しません。
スレッド 1 がまだプリンターで処理されていないため、スレッド 2 は起動しません。

そもそもスレッド 1 をスリープ状態にするのは間違っていると思います。両方のリソースを取得しました。他に何を待っているのでしょうか?

同期を使いすぎている可能性もあります。通常、単純なsynchronizedブロック (モニター) またはwait/notify呼び出し (セマフォ) で十分です。あなたは両方を使用しています。

ここでの経験則は、「/を使用する場合は、それらを最小限のブロックでラップする」ことだと思います。スレッド 2 のスキャナー ブロックは、呼び出しを超えてプリンター ブロックに拡張されます。waitnotifysynchronizednotify

--
明確にするために:

synchronized (x) { A; }
synchronized (x) { B; }

AとBを同時に実行したくない場合に備えて、モニターです(使用します)。

synchronized (x) { x.wait(); } B;
A; synchronized (x) { x.notify(); }

セマフォを使用して、A が B の前に実行されるようにします。

于 2013-11-15T00:05:56.893 に答える
0

はい、これは次の理由でほぼ完全なデッドロックの例です (Oracle wait() doc):

スレッドはこのモニターの所有権を解放し、別のスレッドがこのオブジェクトのモニターで待機しているスレッドにウェイクアップを通知するまで待機します[...]

そのため、モニター スキャナーは解放されますが、モニター プリンターは解放されません。これが、2 回同期してはならない理由です。

コードには 1 つだけ問題があり、それは偽の wakeupです。誰も notify を呼び出していない状態で、wait 呼び出しが突然起きる可能性があります (ほとんどありませんが)。これは、Java と関係があるというよりも、OS のロック実装の原因ですが、適切な OS で実行すると、数日、数か月、または数年後にデッドロックが発生する可能性があります。

于 2013-11-15T11:22:56.667 に答える
0
I guess, the flow is.. 
Thread 1 : takes scanner lock
Thread 1: takes printer lock
Thread 1: creates and starts 2nd thread

Possible flow: 

Thread 2 : Starts, executes run and goes into deadlock2()
Thread 1: waits for object scanner
Thread 2: Enters lock Scanner 
Thread 2: Notifies lock scanner
Thread 2: stuck as it cant get into printer block as Thread 1 has it
Thread 1: Is waiting for Thread 2 to leave scanner block which it does not.

Result: Thread 2 can not have Printer & Thread 1 can not start executing as Thread 2 even when it is notified scanner , has not left Scanner block.

This is not a proper deadlock as thread 1 has not returned for execution.
于 2013-11-14T23:24:12.143 に答える