The original semantics forvolatile
guaranteed only that reads and writes ofvolatile
fields would be made directly to main memory, instead of to registers or the local processor cache, and that actions on volatile variables on behalf of a thread are performed in the order that the thread requested. In other words, this means that the old memory model made promises only about the visibility of the variable being read or written, and no promises about the visibility of writes to other variables. While this was easier to implement efficiently, it turned out to be less useful than initially thought.
While reads and writes of volatile variables could not be reordered with reads and writes of other volatile variables, they could still be reordered with reads and writes of nonvolatile variables. InPart 1 , you learned how the code in Listing 1 was not sufficient (under the old memory model) to guarantee that the correct value forconfigOptions
and all the variables reachable indirectly throughconfigOptions
(such as the elements of theMap
) would be visible to thread B, because the initialization ofconfigOptions
could have been reordered with the initialization of the volatileinitialized
variable.
Unfortunately, this situation is a common use case for volatile -- using a volatile field as a "guard" to indicate that a set of shared variables had been initialized. The JSR 133 Expert Group decided that it would be more sensible for volatile reads and writes not to be reorderable with any other memory operations -- to support precisely this and other similar use cases. Under the new memory model, when thread A writes to a volatile variable V, and thread B reads from V, any variable values that were visible to A at the time that V was written are guaranteed now to be visible to B. The result is a more useful semantics ofvolatile
, at the cost of a somewhat higher performance penalty for accessing volatile fields.
volatile的语义:
1. 确保对volatile域的读写操作都是直接在主存内进行,不缓存到线程的本地内存中。
2. 在旧的JMM中,volatile域的操作与nonvolatile域的操作之间可以重新排序。但是在JSR133以后,规定volatile操作和其他任何内存操作之间都不允许进行重新排序。
3. 在新的JMM下,当线程A写一个volatile变量V,然后线程B读取V的时侯,任何在写入V时对线程A可见的变量值,都对B可见
第3条很奇怪,感觉有点象synchronized的作用了。是不是线程A写入一个volatile变量时,会将自己的本地缓存中的non-volatile变量刷新到主存中,读一个volatile变量时会更新自己的本地缓存中的non-volatile变量?不然线程B又怎么能够看得见那些nonvolatile变量呢?
关于这个问题,查询了一些资料,有文章认为“volatile字段的读取和写入与进入和退出监视器具有相似的内存一致性效果”(http://blog.csdn.net/lovingprince/archive/2010/04/04/5450246.aspx )
对于volatile变量的读写有一个happens-before的偏序关系
A write to a volatile fieldhappens-before every subsequent read of that same volatile. 这点没有疑问。
Because the write of the volatile variableinitialized
happens after the initialization ofconfigOptions
, the use ofconfigOptions
happens after the read ofinitialized
, and the read ofinitialized
happens after the write toinitialized
, you can conclude that the initialization ofconfigOptions
by thread A happens before the use ofconfigOptions
by thread B. Therefore,configOptions
and the variables reachable through it will be visible to thread B.
在新JMM中使用volatile,可以确保上面的代码是合理的。以下"<"是happens-before的意思
1. “线程A中configOptions初始化” < “线程A中写initialized变量”
2.“线程B中读initialized变量” < “线程B中使用configOptions”
3. “write to volatile field” < “subsequent read of that same volatile”
并且有 action1 < action 2,action2 < action3,那么action1 < action3
所以我们可以得出:“线程A中configOptions初始化”< “线程B中使用configOptions”
也就是说,在使用了volatile变量后,使得non-volatile变量的操作之间也有了happens-before关系。