这里写自定义目录标题
volatile的定义
在学习volatile之前,我们先来了解下java语言对它的定义,Java语言规范第3版中对volatile的定义如下:Java编程语言允许线程访问共享变量,为了 确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言 提供了volatile,在某些情况下比锁要更加方便。如果一个字段被声明成volatile,Java线程内存 模型确保所有线程看到这个变量的值是一致的
volatile如何保证可见性?
java代码
转换为汇编语言
可以看到带有volatile修饰的关键字转换为汇编语言前面多了一个lock的指令!
lock指令在多核处理器下回引发两件事:
1、将当前处理器缓存行的数据协会系统内存中
2、这个写会内存的操作会使在其他cpu里的缓存该内存地址的数据无效
为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内存缓存后再进行操作,但操作完不知道何时会写到内存。如果对声明了volatile的变量进行写操作,jvm就会向处理器发送一条lock前缀的指令,将这个变量所在缓存行的数据写会到系统内存。但是就算写会内存,如果其他处理器缓存的值还是旧的,再执行计算操作就会有问题,所以在多处理器下,为了保证各个处理器的缓存是一致的,就会实现**【缓存一致性协议(MESI)】**,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置为无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。
原理
如下图所示
从图中我们可以看出,线程1和线程2一开始都读取了C的值,都存放在各自的缓存行中,然后线程1把C的值更改了,这个时候各自缓存行中C的值就不相等了,这个时候线程2再读取C的值时,发现C被volatile修饰,等同于时共享变量,就会使该缓存行中C的值失效,从新去内存中拉取C最新的值,这个时候线程2读取的便是C最新的值!
应用
单例模式DCL代码:
public class Test {
static volatile Demo demo;
public static Demo getInstance() {
if (demo == null) {
synchronized (Test.class) {
if (demo == null) {
demo = new Demo();
}
}
}
return demo;
}
}
结语
本章节只是大概介绍下volatile关键字的概念和原理,要想更好的应用需要多看jdk源码、框架源码,路漫漫其修远兮,吾将上下而求索,继续加油!!!!