Official notes say, that
Writing to a volatile field has the same memory effect as a monitor release, and reading from a volatile field has the same memory effect as a monitor acquire.
and
Effectively, the semantics of volatile have been strengthened substantially, almost to the level of synchronization. Each read or write of a volatile field acts like "half" a synchronization, for purposes of visibility.
from here.
Does that mean, that any write to a volatile variable makes executing thread flush its cache into main memory and every read from a volatile field makes the thread reread its variables from main memory?
I am asking because the very same text contains this statement
Important Note: Note that it is important for both threads to access the same volatile variable in order to properly set up the happens-before relationship. It is not the case that everything visible to thread A when it writes volatile field f becomes visible to thread B after it reads volatile field g. The release and acquire have to "match" (i.e., be performed on the same volatile field) to have the right semantics.
And this statement makes me very confused. I know for sure that it's not true for regular lock acquire and release with synchronized statement - if some thread releases any monitor then all changes it made become visibly to all other threads (Update: actually not true - watch best answer). There was even a question about it on stackoverflow. Yet it is stated that for whatever reason this is not the case for volatile fields. I can't imagine any implementation of happens-before guarantee, that doesn't make changes visible to other threads, threads that don't read the same volatile variable. At least imagine an implementation, that doesn't contradict the first two quotes.
Moreover before posting this question I did some research, and there is for example this article, which contains this sentence
After executing these instructions, all writes are visible to all other threads through cache subsystem or main memory.
mentioned instructions are the ones that happen when a write to volatile field is made.
So what's that important note is supposed to mean? Or am I am missing something? Or maybe that note is just plain wrong?
Answer?
After making some more research, I was only able to find this statement in official documentation about volatile fields and their effect on changes in non-volatile fields:
Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable. This means that changes to a volatile variable are always visible to other threads. What's more, it also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change.
from here.
I don't know if that is enough to conclude, that happens-before relation is guaranteed only for threads reading the same volatile. So for now I can only summarize that the results are inconclusive.
But in practice I would recommend considering that changes made by thread A
, when it writes to a volatile field, are guaranteed to be visible to thread B
only if thread B
reads the same volatile field. The above quote from the official source strongly implies that.
After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads.
Same link. So this guarantees, that after a thread releases a lock, all other threads will see all changes made by that thread. ALL changes, not just the ones made inside the lock. – Candracandy