Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Volatile variable and flushes to/reads from main memory

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.

like image 556
Nik Kotovski Avatar asked Aug 05 '18 10:08

Nik Kotovski


People also ask

Where the volatile variables are stored in memory?

There's no reason for a volatile variable to be stored in any "special" section of memory. It is normally stored together with any other variables, including non-volatile ones. If some compiler decides to store volatile variables in some special section of memory - there's nothing to prevent it from doing so.

Which variable is volatile?

Volatile variables have the visibility features of synchronized but not the atomicity features. The values of the volatile variable will never be cached and all writes and reads will be done to and from the main memory.

What is the use of volatile variable in Java?

The volatile modifier is used to let the JVM know that a thread accessing the variable must always merge its own private copy of the variable with the master copy in the memory. Accessing a volatile variable synchronizes all the cached copied of the variables in the main memory.

Why variable is called volatile?

A variable should be declared volatile whenever its value can be changed by something beyond the control of the code section in which it appears, such as a concurrently executing thread.


1 Answers

You are looking at this from an entirely wrong angle. First you are quoting the JLS and than talking about flush, which would be an implementation detail of that specification. The absolute only thing you need to rely on is the JLS, anything else is not bad to know may be, but does not prove right or wrong the specification in any shape or form.

And the fundamental place where you are wrong is this:

I know for sure that it's not true for regular lock acquire...

In practice, on x86, you might be right, but the JLS and the official oracle tutorial mandates that:

When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent acquisition of the same lock.

Happens-before is established for subsequent actions (if you want, read two actions if it is simpler for you). One thread releases the lock and the other acquires it - these are subsequent (release-acquire semantics).

Same things happens for a volatile - some thread writes to that, and when some other thread observes that write via a subsequent read, happens-before is established.

like image 151
Eugene Avatar answered Oct 28 '22 04:10

Eugene