总文档 :文章目录
Github : github.com/black-ant
一 . volatile 基础
1 | java复制代码> volatile 保证内存的可见性 并且 禁止指令重排 |
二 . volatile 深入知识点
1 | java复制代码> 读写主存中的数据没有 CPU 中执行指令的速度快 , 为了提高效率 , 使用 CPU 高速缓存来提高效率 |
三 . volatile 和 synchronized 的区别
- volatile 本质是在告诉 JVM 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取。synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
- volatile 仅能使用在变量级别。synchronized 则可以使用在变量、方法、和类级别的。
- volatile 仅能实现变量的修改可见性,不能保证原子性。而synchronized 则可以保证变量的修改可见性和原子性。
- volatile 不会造成线程的阻塞。synchronized 可能会造成线程的阻塞。
- volatile 标记的变量不会被编译器优化。synchronized标记的变量可以被编译器优化。
注意 :volatile 不能取代 synchronized
四 . volatile 原理
观察加入 volatile 关键字和没有加入 volatile 关键字时所生成的汇编代码发现,加入volatile 关键字时,会多出一个 lock 前缀指令。lock 前缀指令,其实就相当于一个内存屏障。内存屏障是一组处理指令,用来实现对内存操作的顺序限制。volatile 的底层就是通过内存屏障来实现的
- Step 1 : 写volatile的时候生成汇编码是 lock addl $0x0, (%rsp)
- Step 2 : 在写操作之前使用了lock前缀,锁住了总线和对应的地址,这样其他的写和读都要等待锁的释放。
- Step 3 : 当写完成后,释放锁,把缓存刷新到主内存。
- 读volatile就很好理解了,不需要额外的汇编指令,CPU发现对应地址的缓存被锁了,等待锁的释放,缓存一致性协议会保证它读到最新的值。
- 只需要对写volatile的使用用lock对总线加锁就行了,这样其他的读、写操作等待总线释放才能继续读。Lock会让其他CPU的缓存invalide,从内存重新加载数据。
1 | java复制代码// volatile 的内存语义 |
五. volatile 原子性
1 | java复制代码> 我们需要区别 volatile 变量和 atomic 变量 |
六 . volatile 源码
1 | java复制代码TODO : 涉及到源码 ,先留坑 , 具体可以先看 @ https://www.cnblogs.com/xrq730/p/7048693.html |
七 . volatile 实测
1 | java复制代码// 测试原子性 , 结果 ThreadC : ------> count :9823 <------- |
本文转载自: 掘金