Scenario A
A1. Write to a volatile variable
A2. Flush all local non-volatile variable writes to main memory
Scenario B
B1. Read from a volatile variable
B2. Reload all non-volatile variables from main memory to local memory
(using Java 1.8 / 1.5+)
Writing to a volatile variables does not guarantee to flush non-volatile variables1. However, it will introduce a "happens before" relation between the write to the volatile and any subsequent read of the volatile (assuming no intervening writes to it). You can exploit this as follows:
If the actions happen in that order, then Thread B will see updated value of NV in step 4. However, if something (including A) writes to NV after step 2, it is unspecified what Thread B will see at step 4.
In general, using volatiles in this way requires deep and careful reasoning. It is easier and more robust to use synchronized
.
Your example is unclear:
If it is intended to be a description of what the Java programmer must do, it is wrong / nonsensical. Java code cannot flush variables.
If it is intended to be a specification of what must happen at the implementation level (e.g. in the JIT compiled code), it is also wrong.
If it is intended to be a description of what could happen at the implementation level (e.g. in the JIT compiled code), it is correct.
I'm not just being pedantic here. The compiler may decide that it doesn't need to flush all local non-volatiles in Thread A, and it will most likely only reload the ones that it needs in Thread B. How it decides? That's the compiler writers' business!
1 - The JLS does not require hardware specific operations such as flushes. Instead, it requires the compiled code to meet some specific guarantees of memory visibility, and leaves the implementation to the compiler writer.