1
public class Test2 {
    static int count;
    public static void main(String[] args) {
        final Test2 t1 = new Test2();
        final Test2 t2 = new Test2();

        new Thread(new Runnable() {

            @Override
            public void run() {
                t1.foo();
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                t1.bar();
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                t2.foo();
            }
        }).start();
    }
    public static synchronized void foo() {
        synchronized (Test2.class) {
            System.out.println("run bar"+count++);
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public static synchronized void bar() {
        System.out.println("run bar");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

上記は私が試したコードです。同期された1つのクラス(Test2.class)にすべてのコードを記述したところ、奇妙なことが起こりました。foo()メソッドを呼び出した後、すぐにbar()メソッドを呼び出すことができません。同じオブジェクトをロックしていると思います。この奇妙なことを説明する方法。

4

1 に答える 1

2

コードが開始する 3 つのスレッドすべてが、Test2 クラスで同じロックを取得します。で始まるメソッドを書くとき

static synchronized

つまり、クラス オブジェクトのロックを取得する必要があります。

foo メソッドの同期ブロックは冗長です。静的同期を使用する場合と同じクラスを使用してロックすることを指定します。組み込みロックは再入可能であるため、これは問題になりません。

とにかく、各スレッドはロックを取得し、完了するまで実行してから、ロックを解放します。インスタンスではなくクラスをロックしているため、スレッドが使用する Test2 のインスタンスは問題ではなく、同じロックを取得して一度に 1 つずつ実行します。

これを実行すると、次の出力が得られました。

c:\Users\ndh>java Test2
run bar0
run bar1
run bar

これらのスレッドが実行される順序は、スケジューラ次第です。t1.foo を呼び出す Runnable が有利なスタートを切ったと推測するのは理にかなっているように思われます。最初に作成されて開始されたので、ロックを取得する競合が発生しないウィンドウがある可能性があります。

于 2017-01-09T11:50:04.377 に答える