使用volatile关键字时内存一致性错误的示例?

来自docs:

使用volatile变量可降低内存一致性错误的风险

但是这意味着有时候volatile变量不能正常工作? 奇怪的是如何使用它 – 我认为这是非常糟糕的代码,有时有时不工作。 我试过谷歌,但没有找到与volatile有关的示例内存一致性错误。 你能提出一个吗?

问题不在于volatile工作不可靠。 它总是以它应该工作的方式工作。 问题是它应该工作的方式有时不适合并发控制。 如果在错误的情况下使用volatile ,仍然可能会出现内存一致性错误。

volatile变量将始终将任何写入传播到所有线程。 但是,假设您需要在各种线程中增加变量。 这样做(*)

 volatile int mCounter; // later, in some code that might be executed simultaneously on multiple threads: mCounter++; 

有可能错过计数器增量。 这是因为在写入新值之前,每个线程需要首先读取mCounter值。 在这两个步骤之间,另一个线程可能已经改变了mCounter的值。 在这种情况下,您需要依赖synchronized块而不是volatile来确保数据完整性。

有关volatilesynchronized更多信息,我推荐Brian Goetz撰写的“ 管理易变性 ”一文

(*)我意识到使用AtomicInteger可以更好地实现上述function; 这是一个人为的例子来说明一个观点。

易失性做到以下几点:

可以防止缓存线程中的值

它确保具有对象字段值的副本的线程与存储器中存在的主副本协调。

确保数据直接写入内存并从内存中读取。

##但是volatile失败的情况:

使Non-Atomic statement Volatile

例如:

 int count = 0; count++; // Increment operator is Not Atomic in java 

##更好的选择:

遵循Brian's Rule总是更好:

When ever we write a variable which is next to be read by another thread, or when we are reading a variable which is written just by another thread, it needs to be synchronized. The shared fields must be made private, making the read and write methods/atomic statements synchronized.

2.第二个选项是使用Atomic Classes ,如AtomicInteger,AtomicLong,AtomicReference等。

##看到这个链接,我问过类似你的问题:

为什么Volatile表现得很奇怪