产生这个问题的原因有2个: 1线程在各自cpu执行,有自己的缓存保存副本,导致和主内存的变量不一致。 2
编译器会对赋值语句进行重新排序。
validate 是一个happens-before很好的例子, volatile
变量强制访问主存,而访问主存肯定被访问 CPU 缓存慢。同时,它还防止 JVM 对程序的优化,这也会降低性能。
当多条语句涉及到对 volatile 变量的访问时,它永远不会将 volatile 变量前的写语句放在 volatile
变量之后,也不会将 volatile 变量读之后的读操作重排序到 volatile 变量之前。
另外,synchronized也可以保证happens-before,即synchronized之前或之内的变量会强制同步主内存。
Memory Consistency Properties
defines
thehappens-beforerelation
on memory operations such as reads and writes of shared variables.
The results of a write by one thread are guaranteed to be visible
to a read by another thread only if the write
operationhappens-beforethe
read operation.
Thesynchronizedandvolatileconstructs,
as well as
theThread.start()andThread.join()methods,
can
formhappens-beforerelationships.
In particular:
Each action in a
thread happens-before every
action in that thread that comes later in the program's order.
1 An unlock
(synchronizedblock or method exit) of a
monitorhappens-beforeevery subsequent lock
(synchronizedblock or method entry) of
that same monitor. And because
thehappens-beforerelation
is transitive, all actions of a thread prior to
unlockinghappen-beforeall actions subsequent to
any thread locking that monitor.
2 A write to
a volatilefieldhappens-beforeevery
subsequent read of that same field. Writes and reads
ofvolatilefields have similar
memory consistency effects as entering and exiting monitors, but
donotentail mutual exclusion
locking.
3 A call
to starton a
threadhappens-beforeany action in the started
thread.
4 All actions in a
thread happen-beforeany other thread
successfully returns from ajoinon that
thread.
The methods of all classes
injava.util.concurrentand its subpackages
extend these guarantees to higher-level synchronization. In
particular:
1 Actions in a thread prior to placing an
object into any concurrent
collection happen-beforeactions
subsequent to the access or removal of that element from the
collection in another thread.
2 Actions in a thread prior to the submission
of a Runnableto anExecutorhappen-beforeits execution begins.
Similarly forCallablessubmitted to
anExecutorService.
3 Actions taken by the asynchronous
computation represented by
a Future
happen-before actions
subsequent to the retrieval of the result
via Future.get() in
another thread.
4 Actions prior to "releasing" synchronizer
methods such as Lock.unlock
, Semaphore.release,
and CountDownLatch.countDown happen-before actions
subsequent to a successful "acquiring" method such
as Lock.lock, Semaphore.acquire, Condition.await,
and CountDownLatch.await on
the same synchronizer object in another thread.
5 For each pair of threads that successfully
exchange objects via
an Exchanger
, actions prior to
the exchange() in
each
thread happen-before those
subsequent to the
corresponding exchange() in
another thread.
6 Actions prior to
calling CyclicBarrier.awaitandPhaser.awaitAdvance(as
well as its variants)happen-beforeactions performed by the
barrier action, and actions performed by the barrier
actionhappen-beforeactions subsequent to a
successful return from the
correspondingawaitin other
threads.