I have read in many posts arguing that System.out.println()
makes code somewhat thread safe, so to simulate the race System.out.println()
should be removed from the code.
Now the write()
method of PrintStream
synchronizes on this
before writing to the stream, so every time write()
is called then a lock is held and released.
write()
method of PrintStream
public void write(int b) {
try {
synchronized (this) { //acquires a lock
ensureOpen();
out.write(b);
if ((b == '\n') && autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
But will that affect the behavior of race?
Suppose:
boolean flag = true;
Thread 1:
System.out.println();
flag = false;
System.out.println();
Thread 2:
System.out.println();
while(flag){
System.out.println();
}
Now if we see then both the threads are locking the same object ie this
(PrintStream), now as the flag
is contained between the two sysouts
, which are acquiring and releasing the same lock, then flag
value will be flushed from the cache and updated in memory where other threads can see it.
So as simulating race is difficult is there a theoretical possibility that this code will be thread safe and Thread 2 will see the changes made to flag
?
If yes then can the same effect of volatile
be achieved using System.out.println();
?
The JLS has the following to say on the topic:
An unlock on a monitor happens-before every subsequent lock on that monitor.
(17.4.5)You can read up on the exact definitions of happens-before, etc. in the JLS but what this basically means is that every read and write that has happened in a thread before it unlocks the lock will be seen by another thread that acquires the lock (careful! If there was a thread 3 who wrote to flag without acquiring the lock there would be no synchronization necessary)
Since you're locking on the same object in this case, this means that yes, it's guaranteed that the updated
flag
value will have to be seen by Thread 2.Although I don't see any mention in the documents that it is guaranteed that the PrintStream acquires a lock and is thread-safe to use, so you're relying on an implementation detail here (one that is very unlikely to ever be broken though).