1. 介绍

本文是我看了并发编程网“聊聊并发”系列文章的总结。查看完整原文地址点我查看

2. volatile

这个东西其实已经讨论了好多次了,在我们的博客里面可以看内存屏障和volatile语义

但是之前的总结总感觉比较啰嗦,没把核心内容用精炼的话总结出来。这次再来对volatile做一次总结。

2.1 为什么使用volatile

开销小:volatile修饰符如果使用得当将会有更小的开销,因为它不会引起线程上下文的切换和调度。

2.2 volatile如何保证可见性以及内存屏障的含义

线程可见性:java线程内存模型确保所有线程看到这个变量的值是一致的

如何实现可见性:之所以有线程可见性的问题主要是由于CPU高速缓存(有的也称作线程工作内存)和系统内存的数据一致性问题。为了解决这个问题CPU设计上引入了“缓存一致性”协议以及内存屏障(高速缓存的读屏障和写屏障)来保证可见性,从而使得线程工作内存和主存的数据达到“最终一致性”。

关于CPU高速缓存(线程工作内存)和系统内存之间的关系可以看下图:

2.3 CPU缓存一致性协议(核心就是发送信号控制CPU高速缓存无效化)

Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。它核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。

2.4 内存屏障

内存屏障有4种。简单来说他们就是保证高速缓存读写时的顺序性,避免指令重排序。然后配合缓存一致性协议就可以保证可见性了。

2.5 使用volatile场景

volatile使用要满足以下2个条件:
 1)对变量的写操作不依赖于当前值
 2)该变量没有包含在具有其他变量的不变式中

最佳实践:仅仅在作为状态标记量的时候使用volatile,其他时候就别使用了。

2.6 总结

一句话总结volatile的定义、实现原理和场景—— volatile是一种依靠内存屏障(避免指令重排序)和缓存一致性协议(依靠设置缓存失效保证缓存主存最终一致性)来保证内存可见性的开销较小的变量修饰符,可被用于状态标记量。