2
class Callme {
   void call(String msg) {
      System.out.print("[" + msg);
      try {
         Thread.sleep(10);
      } catch (InterruptedException e) {
         System.out.println("Interrupted");
      }
      System.out.println("]");
   }
}


class Caller implements Runnable {
   String msg;
   Callme target;
   Thread t;
   public Caller(Callme targ, String s) {
      target = targ;
      msg = s;
      t = new Thread(this);
      t.start();
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
   }

   // synchronize calls to call()
   public void run() {
      synchronized(target) { // synchronized block
         target.call(msg);
      }
   }
}

class Synch {
   public static void main(String args[]) {
      Callme target = new Callme();
      Caller ob1 = new Caller(target, "Hello");
      Caller ob2 = new Caller(target, "Synchronized");
      Caller ob3 = new Caller(target, "World");

      // wait for threads to end
      try {
         ob1.t.join();
         ob2.t.join();
         ob3.t.join();
      } catch(InterruptedException e) {
         System.out.println("Interrupted");
      }
   }
}

このプログラムでは、System.out.print("rahul") なしで同期ブロックを使用すると、完全な出力が出力されますが、SOP("rahul") のこれらの不要なステートメントを配置すると、出力が歪むのはなぜですか?

4

3 に答える 3

1

System.out.printlnメッセージによって3つのCallerメッセージの順序が変わると思います。

  Caller ob1 = new Caller(target, "Hello");
  Caller ob2 = new Caller(target, "Synchronized");
  Caller ob3 = new Caller(target, "World");

ここでは注文が保証されていません。オブジェクトが最初に構築されたとしても"Hello" Caller、それはそのrun()メソッドが実際に最初に実行されるという意味ではありません。synchronized各スレッド内のブロックへの競争はまだあります。"World"たとえば、文字列を最初に印刷できます。

一連のSystem.out.println("rahul");呼び出しを追加することで、プログラムのタイミングに影響を与えているように聞こえます。基になるPrintStreamオブジェクトは同期されているため、他のオブジェクトをロックしている場合でも、他のスレッドのロックに影響します。同期はメモリバリアを超え、スレッド間のキャッシュフラッシュとメモリコピーを引き起こし、スレッドの実行順序や速度などに影響を与える可能性があります。プログラムを1000回実行すると、さまざまな出力の組み合わせが表示されます。これが競合状態の性質であり、予測できません。

于 2012-05-16T14:02:48.803 に答える
0

コンストラクターからスレッドを開始し、このインスタンスをスレッドに渡します。呼び出し元は完全に構築されていないため、そのメンバー変数はrunメソッドでまだ初期化されていない可能性があります。

余分なprintlnにより、バグを確認できます。

Runnablesは作業を定義する必要があり、呼び出し元のコードはスレッドを処理する必要があります。Runnableはそれ自体を実行するべきではありません。

また、最終変数で同期する必要があります。

class Caller implements Runnable {
   final String msg;
   final Callme target;

   public Caller(Callme targ, String s) {
      target = targ;
      msg = s;
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
      System.out.println("rahul");
  }

  // synchronize calls to call()
  public void run() {
     synchronized(target) { // synchronized block
        target.call(msg);
     }
  }
}

class Synch {
 public static void main(String args[]) {
  Callme target = new Callme();
  Thread ob1 = new Thread(Caller(target, "Hello"));
  Thread ob2 = new Thread(Caller(target, "Synchronized"));
  Thread ob3 = new Thread(Caller(target, "World"));

  obj1.start();
  obj2.start();
  obj3.start();

  // wait for threads to end
  try {
     ob1.t.join();
     ob2.t.join();
     ob3.t.join();
  } catch(InterruptedException e) {
     System.out.println("Interrupted");
  }

}}

于 2012-05-16T14:19:57.860 に答える
0

各個人System.out.println()は内部的に同期されているため、単一のprintln()呼び出しからの出力が文字化けすることはありません。

ただし、 への複数の呼び出し間で同期は行われませんprintln()。複数のスレッドが同時に同じ印刷ストリームに書き込む場合、それらのメッセージが表示される相対的な順序は保証されません。

特定の順序が必要な場合は、自分でスレッドを同期する必要があります。

于 2012-05-16T13:59:20.037 に答える