why output comes different everytime instead of sy

2019-07-08 09:26发布

问题:

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

in this program when i use a synchronized block without System.out.print("rahul") it prints perfect output but when i put these unnecessary statement of SOP("rahul") output gets distorted why is it happening instead of synchronization?

回答1:

I will assume that the System.out.println messages cause your 3 Caller messages to change order:

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

There is no guaranteed order here. Even if the "Hello" Caller object is constructed first, that doesn't mean that its run() method will actually be executed first. There is still a race to the synchronized block inside each of the threads. The "World" string could be printed first for example.

By adding your series of System.out.println("rahul"); calls, it sounds like you are affecting the timing of the program. The underlying PrintStream object is synchronized so it will affect the locking in the other threads even if they are locking on another object. Any synchronization crosses a memory barrier which causes cache flushing and memory copying between threads and can affect their run order, speed, etc.. If you ran your program 1000 times you would see many different output combinations. That's the nature of race conditions -- they are unpredictable.



回答2:

Each individual System.out.println() is internally synchronized, so no output from a single println() call should get garbled.

However, there's no synchronization across multiple calls to println(). If multiple threads concurrently write to the same print stream, the relative order in which their messages will appear is not guaranteed.

If you require a particular ordering, you'll have to synchronize the threads yourself.



回答3:

Your starting a thread from a constructor and passing an instance of this into the thread. Caller has not been fully constructed so its member variables may not have been initialized yet in the run method.

The extra println is allowing the bug to be seen.

Runnables should define the work, and calling code should handle the threads. Runnables should not run themselves.

You should also sync on final variables.

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

} }