8

I was trying to create a few scenarios to demonstrate visibility issues while sharing variable across threads. And I noticed that in almost all the cases I tested, if inside run() I added a System.out.println() statement in the same block of code where I am using the shared variable, the visibility issue is not producible. I will provide one example:

Configuration details - Oracle Java6 64bit, Eclipse Juno SR 2

  • 1)WITH VISIBILITY ISSUE:

    public class NoVisibility_Demonstration extends Thread {
    boolean keepRunning = true;
    public static void main(String[] args) throws InterruptedException {
        NoVisibility_Demonstration t = new NoVisibility_Demonstration();
        t.start();
        Thread.sleep(1000);
        t.keepRunning = false;
        System.out.println("keepRunning is false");
    }
    public void run() {
        int x = 1;
        while (keepRunning) 
        {
            //System.out.println("If you uncomment this line, the code will work without the visibility issue");
            x++;
    
        }
        System.out.println("x:"+x);
    }
    

    }

OUTPUT: The thread keeps running infinitely

  • 2) WITHOUT VISIBILITY ISSUE:

THE SAME CODE AS ABOVE, WITH THE UNCOMMENTED println() STATEMENT IN THE run()

OUTPUT:

...

If you uncomment this line, the code will work without the visibility issue

If you uncomment this line, the code will work without the visibility issue

If you uncomment this line, the code will work without the visibility issue

x:19391

keepRunning is false

Since I noticed similar behavior in all the examples I tried, I am wondering if there is any data integrity check by JVM before any I/O operation.

Biman Tripathy
  • 2,766
  • 3
  • 23
  • 27
  • 3
    Using `System.out.println()` in that `while` loop is going to have a fairly significant impact on how quickly each loop iteration takes to complete. Writing to the console is *slow*, simply incrementing an `int` variable is very fast. Just something to bear in mind. – JonK Dec 16 '15 at 12:11
  • @JonK I have noticed that in another program I wrote. And yes, the difference is tremendous. – Biman Tripathy Dec 17 '15 at 06:32

2 Answers2

10

PrintWriter is synchronized

public void println(String x) {
    synchronized(this) {
        this.print(x);
        this.newLine();
    }
}

Two sequential calls of System.out.println() in main thread and in second thread create a synchronization order between two threads. That means that all actions (in your case it is variable update), that happened in main thread before releasing a monitor (exiting synchronized method) will be seen by the code, executed in second thread after it acquires a monitor (enter synchronized method).

In simple words, yes, calling System.out.println() makes this synchronization.

AdamSkywalker
  • 11,408
  • 3
  • 38
  • 76
  • Thanks. Much clarity now. Although I see that there is no impact on this observation irrespective of whether or not I comment the println() statement in main thread. Only the println() in the run() causes a difference. Also, there is no impact even if i put a println() statement before starting the other thread from main. – Biman Tripathy Dec 17 '15 at 06:45
  • @BimanTripathy i have no idea why you get these results. are they stable? – AdamSkywalker Dec 18 '15 at 11:40
  • yes. the behavior is produced every time. do you mean you are not getting the same results as I am getting? – Biman Tripathy Dec 18 '15 at 11:55
  • ok, got it. It is because in this case it doesn't make a difference whether the main thread is aware of the correct state of the shared variable. Enlightened! thanks – Biman Tripathy Dec 18 '15 at 12:05
2

This behaviour is implementation specific. In OpenJDK, println's body is synchronized altough the API does not state that it is.

Pétur Ingi Egilsson
  • 4,368
  • 5
  • 44
  • 72