3

別のメソッド内で同期ステートメントを使用して 1 つのメソッドを実行しようとしています。

私のクラス

public class MyClass {

    private Object lockObject = new Object();

    public void testFirst() {
        synchronized (lockObject) {
            System.out.println("Entered testFirst() sync");
            testSecond();
            System.out.println("Leaving testFirst() sync");
        }
    }

    private void testSecond() {
        synchronized (lockObject) {
            System.out.println("Entered testSecond() sync");
        }
    }

}

主要

package com.replanet;

public class Main {

    public static void main(String[] args) {

        MyClass myClass = new MyClass();
        myClass.testFirst();
    }

}

出力

Entered testFirst() sync
Entered testSecond() sync
Leaving testFirst() sync

私は別の出力を期待していました。

Entered testFirst() sync
Leaving testFirst() sync
Entered testSecond() sync

仕事が終わるtestSecond()まで待たないのはなぜですか?testFirst()

4

6 に答える 6

4

各ロックはそれを要求するスレッドに関連付けられており、ロックを取得すると、ロックを解除するまでそれを保持するため、この一見奇妙な動作が見られます。

あなたのコードでは同じロックを2回取得しているので、2回目の試行はすでに持っているので、すぐに成功します。

参考のためにここを参照してください:

1つのスレッドがオブジェクトの同期メソッドを実行している場合、同じオブジェクトブロックの同期メソッドを呼び出す他のすべてのスレッドは、最初のスレッドがオブジェクトで完了するまで実行を一時停止します。

于 2013-02-25T11:27:42.880 に答える
3

最初のセクションに入るにはsynchronized、オブジェクトのロックが必要lockObjectです。2番目のセクションに到達してsynchronizedも、まだそれがあるので、続行します。を実行するtestFirstと、のsynchronizedブロックはtestSecond何も変更しません。

于 2013-02-25T11:28:00.727 に答える
2

次の点に注意してください。

  • synchronizedブロックは再入可能です。synchronizedステートメントを介してロックを保持するsynchronizedと、同じモニターを使用して別のブロックに入ることができます-あなたの場合、からの呼び出しを妨げるものは何もありませtestSecondtestFirst
  • ここで、2 つのメソッドが異なるモニターを使用したと想像してください。他のスレッドがロックを保持していないため、同じ出力が得られます。testSecond
  • 2 つのメソッドが 2 つの異なるロックを使用し、別のスレッドが の実行で使用されたロックを保持してtestSecondtestFirst場合、呼び出しをスキップして先testSecondに進むことはなく、ロックが再び使用可能になるまでブロックされます。
于 2013-02-25T11:55:39.690 に答える
1

Beause testSecond()はtestFirst()に関連付けられています

以下のような制御フロー:-

System.out.println("Entered testFirst() sync");
       System.out.println("Entered testSecond() sync");
System.out.println("Leaving testFirst() sync");
于 2013-02-25T11:30:54.720 に答える
1

同期は、固有ロックまたはモニター ロックと呼ばれる内部エンティティを中心に構築されます。
すべてのオブジェクトには固有のロックが関連付けられています。慣例により、オブジェクトのフィールドへの排他的かつ一貫したアクセスが必要なスレッドは、オブジェクトにアクセスする前にオブジェクトの固有ロックを取得し、それらの操作が完了したら固有ロックを解放する必要があります。スレッドは、ロックを取得してからロックを解放するまでの間、固有のロックを所有していると見なされます。スレッドが固有ロックを所有している限り、他のスレッドが同じロックを取得することはできません。他のスレッドは、ロックを取得しようとするとブロックされます。

したがって、スレッドはlockObjectの所有者であるため、lockObjectを使用してブロック内のすべてのコードに入ることができます

于 2013-02-25T11:37:53.783 に答える
0

投稿したコードを編集しました。そして、同期ステートメントは理にかなっていますね。

私のクラス

public class MyClass {

    private Object lockObject = new Object();

    public void testFirst() throws InterruptedException {
        // Here is something that should not be synchronized 
        synchronized (lockObject) {
            System.out.println("testFirst() is about to fall asleep. "
                    + Thread.currentThread().getName());
            Thread.sleep(2000);
            System.out.println("testFirst() woke up. " + Thread.currentThread().getName());
        }
    }

}

マイスレッド

public class MyThread extends Thread {

    private MyClass myClass;

    public MyThread(MyClass myClass) {
        this.myClass = myClass;
    }

    @Override
    public void run() {
        try {
            myClass.testFirst();
        } catch (InterruptedException e) {
            interrupt();
        }
        super.run();
    }

}

使用法

package com.replanet;

public class Main {

    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        MyThread mThread = new MyThread(myClass);
        MyThread anotherThread = new MyThread(myClass);
        mThread.start();
        anotherThread.start();
    }

}

出力

testFirst() is about to fall asleep. Thread-0
testFirst() woke up. Thread-0
testFirst() is about to fall asleep. Thread-1
testFirst() woke up. Thread-1
于 2013-02-25T14:16:14.543 に答える