If I have a thread constantly invoke getV and I just do setV once in
another thread, Is that reading thread guaranteed to see the new value
right after writing?
NO, the reading thread may just read its own copy (cached automatically by the CPU Core which the reading thread is running on) of V
's value, and thus not get the latest value.
Or do I need to make "V" volatile or AtomicReference?
YES, they both works.
Making V
volatile simply stop CPU Core from caching V
's value, i.e. every read/write operation to variable V
must access the main memory, which is slower (about 100x times slower than read from L1 Cache, see interaction_latency for details)
Using V = new AtomicInteger()
works because AtomicInteger
use a private volatile int value;
internally to provide visiblity.
And, it also works if you use lock (Lock
object, synchronized
block or method; they all works) on reading and writing thread (as your second code segment does), because (according to the Second Edition of The Java ® Virtual Machine Specification section 8.9)
...Locking any lock conceptually flushes all variables from a thread's
working memory, and unlocking any lock forces the writing out to main
memory of all variables that the thread has assigned...
...If a thread uses a particular shared variable only after locking a
particular lock and before the corresponding unlocking of that same
lock, then the thread will read the shared value of that variable from
main memory after the lock operation, if necessary, and will copy back
to main memory the value most recently assigned to that variable
before the unlock operation. This, in conjunction with the mutual
exclusion rules for locks, suffices to guarantee that values are
correctly transmitted from one thread to another through shared
variables...
P.S. the AtomicXXX
classes also provide CAS
(Compare And Swap) operations which is useful for mutlthread access.
P.P.S. The jvm specification on this topic has not changed since Java 6, so they are not included in jvm specification for java 7, 8, and 9.
P.P.P.S. According to this article, CPU caches are always coherent, whatever from each core's view. The situation in your question is caused by the 'Memory Ordering Buffers', in which the store
& load
instructions (which are used to write and read data from memory, accordingly) could be re-ordered for performance. In detail, the buffer allows a load
instruction to get ahead of an older store
instruction, which exactly cause the problem (getV()
is put ahead so it read the value before you change it in the other thread). However, in my opinion, this is more difficult to understand, so "cache for different core" (as JVM specs did) could be a better conceptual model.