作为解决上篇中提到的多线程环境下的memory visibility问题，java提供了一种比同步（synchronization）机制相对弱的一种形式--Volatile 变量，来确保更新一个多线程共享变量可以以一种可预告的方式通知其他线程。volatile变量并不缓存到寄存器中（registers）或者缓存到其他处理器（多处理器环境，register只能被包含它的处理器看见）看不见的地方，因此对于volatile变量的读取总是会返回最新的结果（因为没有使用缓存）
The Java language also provides an alternative, weaker form of synchronization, volatile variables, to ensure that updates to a variable are propagated predictably to other threads. When a field is declared volatile, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread.
Yet accessing a volatile variable performs no locking and so cannot cause the executing thread to block, making volatile variables a lighter-weight synchronization mechanism than synchronized.
Volatile reads are only slightly more expensive than nonvolatile reads on most current processor architectures.
So from a memory visibility perspective, writing a volatile variable is like exiting a synchronized block and reading a volatile variable is like entering a synchronized block. However, we do not recommend relying too heavily on volatile variables for visibility; code that relies on volatile variables for visibility of arbitrary state is more fragile and harder to understand than code that uses locking.
Use volatile variables only when they simplify implementing and verifying your synchronization policy; avoid using volatile variables when veryfing correctness would require subtle reasoning about visibility. Good uses of volatile variables include ensuring the visibility of their own state, that of the object they refer to, or indicating that an important lifecycle event
(such as initialization or shutdown) has occurred.
The most common use for volatile variables is as a completion, interruption, or status flag。
Volatile variables can be used for other kinds of state information, but more care is required when attempting this. For example, the semantics of volatile are not strong enough to make the increment operation (count++) atomic, unless you can guarantee
that the variable is written only from a single thread.
结论：Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.You can use volatile variables only when all the following criteria are met:
Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value;
The variable does not participate in invariants with other state variables; and
Locking is not required for any other reason while the variable is being accessed.