3

I have read following article from SO

Difference between synchronization of field reads and volatile

here questioner writes

the point of the synchronization is to ensure that the value of acct.balance that are read by this thread is current and that any pending writes to the fields of the object in acct.balance are also written to main memory.

most popular answer:

You are correct.

please research this code:

public class VolatileTest {

    static/* volatile */boolean done = false;

    public VolatileTest() {
        synchronized (this) {

        }

    }

    public static void main(String[] args) throws Exception {
        Runnable waiter = new Runnable() {
            public void run() {
                while (!done)
                    ;
                System.out.println("Exited loop");

            }
        };
        new Thread(waiter).start();
        Thread.sleep(100); // wait for JIT compilation
        synchronized (VolatileTest.class) {
            done = true;
        }
        System.out.println("done is true ");
    }

}

On my pc this program doesn't terminate.

Thus I think that

  1. if I change volatile variable I will see actual value in another thread for any outstanding everywhere!
  2. if I change variable in synchronized section with monitor "A" I will see actual value only in synchronized section with monitor "A"(for example in another thread)

Am I correct ?

Community
  • 1
  • 1
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • The term "main memory" is a loose term here. It only means a consistent view. The L2 caches talk to each other to make this happen so the change might not even be in L3 cache, let alone main memory. – Peter Lawrey Apr 28 '14 at 12:53
  • @Peter Lawrey I have not enough knowledge about CPU. I didn't understand anything – gstackoverflow Apr 28 '14 at 19:44
  • This talks about how caches stay in sync. http://en.wikipedia.org/wiki/Cache_coherence Generally caches talk to each other, bypassing main memory as the caches are faster, by design. This will tell you more than you need to know about CPU caches http://en.wikipedia.org/wiki/CPU_cache – Peter Lawrey Apr 29 '14 at 07:11

2 Answers2

3
  1. Yes, that is true because volatile write happens-before written value can be read from the variable.
  2. Not exactly. There is a guarantee that another thread synchronized on the same monitor will see the updated value, because monitor release happens-before same monitor acquire by another thread. Without acquiring the same monitor, the other threads may see the updated value. The "only" in your formulation is too strong :)
Alexey Malev
  • 6,408
  • 4
  • 34
  • 52
  • But surely the thread should see the updated value eventually even without a monitor? Even if the memory is inconsistent for some time in this case shouldn't the loop detect the flipped bool after a while? – monocell Apr 28 '14 at 11:52
  • @monocell This can happen, and can not happen - we do not have any guarantees when this will happen, and if this will ever happen at all. – Alexey Malev Apr 28 '14 at 11:54
  • I had no idea, I though any transformation could be explained by reordering of the effects of a statement, not a complete lack of effects. And to think people pay me for writing java code. :( – monocell Apr 28 '14 at 12:02
  • @Alexey While I agree with the answer - Core i7 does out-of-order and general reordering (and always did). I would be very surprised they deprecated such a major speedup technology in high-performance chips. – Ordous Apr 28 '14 at 12:15
  • @Alexey Well the rest of it was to the point - indeed caches, OS and physical memory model and architecture influence the behavior, it's just that one point that struck me as odd. – Ordous Apr 28 '14 at 12:20
  • Reading through the memory model docs, Are you sure this is not a question of `Observable Behavior and Nonterminating Executions`? i.e. A thread that also prints the value is guaranteed to eventually see the updated value? Or am I reading the whole thing wrong? I seem to be unable to find the part where they describe things that can't be explained by reordering. – monocell Apr 28 '14 at 12:34
  • @monocell Honestly, I can't say that for sure. For sure I can say things that are in the answer :) – Alexey Malev Apr 28 '14 at 12:37
  • @Ordous Yep, but the time limit for editing the comment already expired :( – Alexey Malev Apr 28 '14 at 12:38
  • 1
    @monocell The case of non-termination due to multithreading is touched very briefly there. In fact the whole thing is very mathematical and hard to get your head around it. This particular case is due to "Furthermore, if an action y is in O, and either hb(x, y) or so(x, y), then x is in O" This says - unless there is a deadlock (or other types of locks), if there is a HB relationship - you will eventually see variable changes. However, this does not specify what happens without HB. In fact, it even defines hanging as allowable in case there are no actions in a thread that may prevent it. – Ordous Apr 28 '14 at 12:51
  • @Alexey Malev **if I change variable in synchronized section with monitor "A" I guaranteed to see actual value only in synchronized section with monitor "A"(for example in another thread) ?** Is it valid formulation? – gstackoverflow Apr 28 '14 at 12:58
  • @gstackoverflow Closer, but still no. The word only is too strict. There are other possibilities - volatile variable, thread start, thread death or thread interrupt, object creation. The oracle docs have the short and correct formulation (although it is not easily understandable) – Ordous Apr 28 '14 at 13:10
  • @Ordous **volatile variable** - accepted. *thread start, thread death or thread interrupt, object creation.* Can you show example? – gstackoverflow Apr 28 '14 at 13:14
  • @gstackoverflow From the Synchronization Order subchapter: The final action in a thread T1 synchronizes-with any action in another thread T2 that detects that T1 has terminated. T2 may accomplish this by calling T1.isAlive() or T1.join(). As such, if the isAlive() with negative result happens before the read (if clause for once), then write is before thread termination, is before isAlive(), is before read -> Write visibility is guaranteed. – Ordous Apr 28 '14 at 13:19
2

You are correct)

The memory model is described here: Java Memory Model

In particular, it states:

An unlock on a monitor happens-before every subsequent lock on that monitor.

AND

A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.

As such, only locks and unlocks on the same monitor will behave how you want, also all writes and reads of a volatile variable. Hence your program may not terminate, as you read without locking said monitor and there is no happens-before relationship.

One thing to note (and this is the reason multithreading bugs are so annoying):
You MAY see the change in other threads. Or may not. On most architectures you will likely see it during normal processing, and maybe a bug will manifest during high load, making it difficult to reproduce. The JVM does not give any guarantees what and when will see it if there is no happens-before (i.e. volatile, synchronized, in same thread or the other cases as in the link), but tries it's best to run smoothly.

Ordous
  • 3,844
  • 15
  • 25