为什么输出每次都不同而不是同步块

时间:2012-05-16 13:55:48

标签: java multithreading synchronization

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”)输出变得扭曲时为什么会发生而不是同步?

3 个答案:

答案 0 :(得分: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次,您会看到许多不同的输出组合。这就是竞争条件的本质 - 它们是不可预测的。

答案 1 :(得分:0)

每个人System.out.println()都在内部同步,因此单个println()来电的输出不会出现乱码。

但是,对println()的多次调用没有同步。如果多个线程同时写入同一个打印流,则无法保证其消息的相对顺序。

如果您需要特定的订购,则必须自己同步线程。

答案 2 :(得分:0)

从构造函数中启动一个线程并将其实例传递给线程。调用者尚未完全构造,因此其成员变量可能尚未在run方法中初始化。

额外的println允许看到bug。

Runnables应该定义工作,调用代码应该处理线程。 Runnables不应该自己运行。

您还应同步最终变量。

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

} }