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消息会导致您的 3Caller条消息更改顺序:

  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

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

额外的 println 允许看到错误。

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

} }

于 2012-05-16T14:19:57.860 回答
0

每个人System.out.println()都是内部同步的,因此单个println()调用的输出不应出现乱码。

但是,多次调用println(). 如果多个线程同时写入同一个打印流,则不能保证它们的消息出现的相对顺序。

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

于 2012-05-16T13:59:20.037 回答