0

同期メソッドまたは同期ブロックを使用して異なる結果が生成されるシナリオを観察しました。以下のコードから:

class Callme {
    void call(String msg) {
        System.out.print("[" + msg);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("]");
    }       
}

class Caller implements Runnable{
    String msg;
    Callme target;
    Thread t;

    public Caller(Callme target, String msg) {
        this.target = target;
        this.msg = msg;
        t = new Thread(this, "Caller thread");
        t.start();
    }

    @Override
    public void run() {
        synchronized(target) {
            target.call(msg);
            new Callme().call(msg);
        }
    }

}

public class Test {

    public static void main(String[] args) throws InterruptedException {
        Callme obj = new Callme();

        new Caller(obj, "thread1");
        new Caller(obj, "thread2");
        new Caller(obj, "thread3");

        Thread.currentThread().join();
    }
}

Caller::run メソッドで同期ブロックを使用すると、出力は次のように同期されます。

[thread1]
[thread1]
[thread3]
[thread3]
[thread2]
[thread2]

しかし、同期ブロックの代わりに Callme::call メソッドに同期メソッドを使用すると、出力が同期されません。

[thread1]
[thread1[thread2]
]
[thread3[thread2]
]
[thread3]

私の期待は、「Callme::call」メソッドを呼び出すときに異なるオブジェクトを使用しているため、両方のケースで出力が同期されるべきではないということです

これにより、同期ブロックの概念についての私の理解に疑問が生じましたか?

4

1 に答える 1

1

synchronized(this)同期されたメソッドは、メソッド全体の長さの -blockと同等ですが、コードは を使用synchronized(target)してtargetおり、 の共有インスタンスですCallme。つまり、同期されるオブジェクトが異なるため、動作は同じではありません。

を使用する場合synchronized(target)、すべてのスレッドが の同じインスタンスで同期するため、動作がシリアルになります。スレッドは、メソッドの全期間にわたってCallmeそのインスタンスのモニターを保持するため、実際には、スレッドはメソッドの後に 1 つずつ実行されます。他の。CallmeCaller.run

同期されたメソッドの場合、スレッドはそれぞれ の独自のインスタンスで同期するCallerため、実際にはシリアル化はありません ( への書き込みを除くSystem.out)。

いくつかの追加のコメント:

  • それ自体で待機するため、呼び出しThread.currentThread().join()は悪い考えです
  • Thread一般に、そのスレッドによって実行される実装でインスタンスを作成および開始しないRunnableでください。スレッドへのアクセスが失われます。部分的に構築されたオブジェクトを にパブリッシュしているため、特にコンストラクタでこれを行わないでください。これは、Threadこのコードでは大きな問題ではありませんが、より複雑なアプリケーションでは微妙なバグにつながる可能性があります。
于 2016-12-22T13:01:44.227 に答える