volatile的特性
可见性:对一个volatile修饰的变量的读总是能看到(任意线程)对这个volatile修饰变量最后的写入值。
原子性:对任意单个volatile修饰的变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性(基于这点,我们通常会认为volatile不具备原子性)。volatile仅仅保证对单个volatile变量的读/写具有原子性,而锁的互斥执行的特性可以确保对整个临界区代码的执行具有原子性。
有序性:对一个volatile修饰的变量的读写操作前后加上各种特定的内存屏障来禁止指令重排序来保障有序性。
volatile读—写的内存语义
当读一个volatile修饰的变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将冲主内存中读取共享变量值。
当写一个volatile修饰的变量时,JMM会把线程对应的本地内存中的共享变量值刷新到主内存。
volatile可见性实现原理
JMM内存交互层面实现
volatile修饰的变量的read、load、use操作和assign、store、write操作必须是连续的,即修改后必须立即同步回主内存,使用时必须从主内存刷新,由此保证volatile修饰的变量操作对多线程的可见性。
硬件层面实现
通过lock前缀指令,会锁定变量缓存行区域并写回主内存,这个操作称为缓存锁定,缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据。一个处理器的缓存回写到内存会导致其他处理器的缓存无效。
lock前缀指令的作用:
确保后续指令执行的原子性。在Pentium及之前的处理器中,带有lock前缀的指令在执行期间会锁住总线,使得其它处理器暂时无法通过总线访问内存,很显然,这个开销很大。在新的处理器中,Intel使用缓存锁定来保证指令执行的原子性,缓存锁定将大大降低lock前缀指令的执行开销。
LOCK前缀指令具有类似于内存屏障的功能,禁止该指令与前面和后面的读写指令重排序。
LOCK前缀指令会等待它之前所有的指令完成、并且所有缓冲的写操作写回内存(也就是将store buffer中的内容写入内存)之后才开始执行,并且根据缓存一致性协议,刷新store buffer的操作会导致其他cache中的副本失效。
volatile关键字确保了多线程环境下的可见性和有序性,但不保证复合操作的原子性。它的实现涉及到JMM内存模型以及硬件层面的锁前缀指令,如缓存锁定和内存屏障,以保证数据同步和避免指令重排序。
1228

被折叠的 条评论
为什么被折叠?



