2016-12-22 8 views
0

同期メソッドまたは同期ブロックを使用して異なる結果を生成するシナリオを観察しました。コードの下から :私はCallmeのための同期方法を使用する場合同期メソッドとブロックの動作が異なる

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

しかし:

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(); 
    } 
} 

私は出力に含まを以下のように同期されている発信者:: runメソッドにsynchronizedブロックを使用します。 :callメソッドは、代わりに同期ブロックの、出力が同期していない:

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

私の期待は、出力は両方のケースのBECAに同期させるべきではないです私は "Callme :: call"メソッドを呼び出すときに別のオブジェクトを使用しています

これは私に同期ブロックの概念についての質問になりましたか?

答えて

1

同期方法は、しかし、コードがsynchronized(target)を使用して、方法全体の長さsynchronized(this) - ブロックに相当し、targetCallmeの共有インスタンスです。言い換えれば、同期されるオブジェクトが異なるため、動作が同じではありません。あなたがsynchronized(target)を使用する場合は

、それはすべてのスレッドがCallmeの同じインスタンス上で同期させるので、彼らの行動はシリアルであることを意味しますスレッドがそうで、Caller.run方法の全期間のためにそのCallmeインスタンスのモニターを開催しますスレッドが順番に実行されるようになります。

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

いくつかの追加の発言:それは実行されようとしているRunnable実装でThreadインスタンスを作成し、起動しない自体に一般的に

  • をお待ちしておりますので、

    • Thread.currentThread().join()を呼び出すには、悪い考えですそのスレッドによって:あなたはスレッドへのアクセスを失います。部分的に構築されたオブジェクトをThreadに公開しているため、特にこのコードで大きな問題ではないが、より複雑なアプリケーションでは微妙なバグが発生する可能性があるため、コンストラクタではこれを行わないでください。
  • 関連する問題