Volatile 关键字实现原理
线程的工作空间是 CPU寄存器和cache
的抽象描述
CPU修改数据 内存数据的步骤 :
- 把内存中的数据读到cache中
- 在cache中更新数据
- 把更新的数据刷新到缓存
数据的不一致问题
解决方案 :
-
总线加锁(粒度太大)
-
MESI()
a. 读操作: 不做任何操作,将cache中的数据读到寄存器中
b. 写操作 : 发出信号通知其他的CPU将该变量的cache line置为无效 ,其他CPU要访问这个变量的时候,只能从内存中获取
Cache line: CPU的cache中会增加很多的cache line,然后将cache 里呢 与对象对应起来
-
Java内存模型
-
主存中的数据所有线程都可以访问
-
每个线程都有自己的工作空间(本地内存)
-
工作空间数据 : 局部变量 .内存的副本
-
线程不能直接修改内存中的数据,只能读到工作空间修改>>寄存器 修改完成后返回刷新到内存
Volatile 关键字语义分析
volatile 作用 ,让其他线程能够马上感知到某一线程的修改
(1) 保证了可见性
对共享变量的修改,其他的线程马上能感知到
不能保证原子性 读.写 (i++) > 多个原子性操作合在一起变为非原子性
(2) 保证有序性
重排序 (编译阶段和指令优化阶段)
输入的程序的代码并不是实际执行的程序
重排序对单线程没有影响 ,对多线程有影响
volatile 规则 :
对于volatile修饰的变量
(1) volatile 之前的代码不能调整到它的后面
(2) volatile 之后的代码不能调整到它的前面
(3) 霸道(位置不变化)
(3) volatile的原理和实现机制(锁,轻量级的锁)
java > class > JVM > ASM文件
汇编中
volatile int a = 0
lock : a
Volatile的使用场景
(1)将其作为对线程操作的标志,控制线程的运行
(2) 双重锁 (double -check -locking)
单例模式
public class Singleton{
private volatile static Singleton instance ;
private Singleton(){}
public static Singleton getInstance (){
if(Instanse == null )
{
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
volatile 与 synchronized的区别
(1) 使用上的区别
volatile 只能修饰变量 ,synchronized可以修饰方法和语句块
(2) 对原子性的保证
synchronized 可以保证原子性,volatile不能保证原子性
(3) 对可见性的保证
均可保证可见性
volatile 对变量加了lock ,synchronized使用monitor 对应的指令 >> monitorEnter monitorexit
(4) 对有序性的保证
volatile 能保证有序性 ,synchronized 可以保证有序性,但是代价(重量级)并发变为串行
(5) 其他
synchronized 引起线程阻塞
volatile 不会
// volatile 只能通知其他线程我正在修改变量,并通知它到内存中去读,但是并不能保证内存中的数据是修改后的新值,有可能读的是旧值