volatile作用:
1.保持线程可见:某个线程每次使用volatile修饰的变量的时候都要去主内存读这个变量到线程内存中;
2.禁止指令重排序:cpu在没有前后因果关系的指令是存在指令先后执行不确定性;
(1)对象的创建过程 :当我们new 一个对象的时候会产生三条汇编指令,分别是 new,invokespecial和astore指令
new -在堆内存中申请了一块new对象的内存大小(new 一个对象16个字节),属性值都是默认(半初始化)
invokespecial - 调用构造方法初始化属性值
astore- 将堆中的数据与栈内存中建立引用关系
主要分这三步骤;
(2)DCL单例: 在单例中对的synchronized 双重检查(防止多线程的判断不一致性)
是否需要加volatile,防止发生指令重排,多线程下情况下拿到半初始化状态的值;
(3)内存屏障:
jvm对volatile修饰的变量实现了读写屏障;jvm 遵循 volatile变量的写操作时间上优先于对这个变量的读操作;这样就避免了cpu的指令重排;
(4)as if serial : 对于线程发生指令重排,不影响单线程汇编码执行的结果
(5)底层通过lock.addl汇编指令(该指令支持缓存一致性协议MESI),把线程中的缓存刷到主内存中,并通知其他线程缓存失效,需要去主内存中读取新的数据,实现数据可见性;
MESI-缓存行的四种状态 修改 独占 共享 失效
(6)现在的CPU是三级缓存,L1,L2,L3, 其中L3是一个cpu内核的共享缓存;CPU从主内存中读取数据是以缓存行单位读取,大小是64个字节;