0

私はJavaでいくつかの演習を行っています(コードがどこから来たのかと思う人もいるかもしれません)。次のコードでデッドロック状態を引き起こそうとします:

class Resource {

    public Integer value = 42;
}

public class DeadLockRisk implements Runnable {

    private Resource resourceA = new Resource();
    private Resource resourceB = new Resource();

    public void write(int a, int b) {

        System.out.println(Thread.currentThread().getName() + " try write Lock A");

        synchronized(resourceA) {

            System.out.println(Thread.currentThread().getName() + " write Lock A");
            System.out.println(Thread.currentThread().getName() + " try write Lock B");

            synchronized(resourceB) {

                System.out.println(Thread.currentThread().getName() + " write Lock B");

                resourceA.value = a;
                resourceB.value = b;
        //sit on it!
        //try { Thread.sleep(5000); } catch (Exception e) {}

        System.out.println(Thread.currentThread().getName() + " release write B");
        }
        System.out.println(Thread.currentThread().getName() + " release write A");
    }
    }

    public int read() {

    Integer retVal;
        System.out.println(Thread.currentThread().getName() + " try read Lock B");

        synchronized(resourceB) {

            System.out.println(Thread.currentThread().getName() + " read Lock B");
            System.out.println(Thread.currentThread().getName() + " try read Lock A");

            synchronized(resourceA) {

                System.out.println(Thread.currentThread().getName() + " read Lock A");
                retVal = resourceB.value + resourceA.value;
        System.out.println(Thread.currentThread().getName() + " release read A");
            }
        System.out.println(Thread.currentThread().getName() + " release read B");
        }
    return retVal;
    }

    public void run() {


    if (Thread.currentThread().getName().equals("Thread-1")) {
        write(1,2);
    }

    System.out.println(read());
    }

    public static void main(String[] args) {

        Thread ta = new Thread(new DeadLockRisk());
        Thread tb = new Thread(new DeadLockRisk());
        ta.start(); tb.start();
    }
}

(javac -version javac 1.6.0_0 uname -a Linux inspiron 2.6.29 #1 SMP Sat May 16 10:56:17 CEST 2009 i686 GNU/Linux)

(他の状況の中でも)以下の出力を取得します。

スレッド 1 書き込みロック A を試行
スレッド 0 読み取りロック B を試行
スレッド 1 書き込みロック A <=====
スレッド 0 読み取りロック B
スレッド 1 書き込みロック B を試行
スレッド 0 読み取りロック A を試行
スレッド 1 書き込みロック B
スレッド 0 読み取りロック A <=====
スレッド 1 解放書き込み B
スレッド 0 解放読み取り A
スレッド 1 リリース書き込み A
スレッド 0 解放読み取り B
Thread-1 try read ロック B
154
スレッド 1 読み取りロック B
Thread-1 try read ロック A
スレッド 1 読み取りロック A
スレッド 1 リリース読み取り A
スレッド 1 リリース読み取り B
3

何が間違っていると思いますか? ロックがスレッド 1 によって解放される前に、スレッド 0 が read() のクリティカル セクションに入り、A のロックを取得する方法さえあります。出力が同期していないため、これは可能ですか? このコードではデッドロックは発生しません。

4

2 に答える 2

5

DeadLockRisk の異なるインスタンスを両方のスレッドに渡すため、同じオブジェクトで同期されません。

于 2009-07-19T16:12:41.363 に答える
1

どちらの DeadlockRisk インスタンスも、resourceA フィールドと resourceB フィールドに対して異なるインスタンスを持ちます。コードを期待どおりに実行する場合は、インスタンス フィールドを静的フィールドに変更します。

于 2009-07-19T16:15:03.107 に答える