volatile原理分析
什么是 Volatile
能够保证线程可见性,当一个线程修改共享变量时,能够保证对另外一个线程可见性,
但是注意他不能够保证共享变量的原子性问题。
Volatile的特性
可见性
能够保证线程可见性,当一个线程修改共享变量时,能够保证对另外一个线程可见性,
但是注意他不能够保证共享变量的原子性问题。
顺序性
程序执行程序按照代码的先后顺序执行。
原子性
即一个操作或者多个操作 要么全部执行并且执行的过程,要么失败。
Volatile可见性
|
public class Mayikt extends Thread {
|
CPU多核硬件架构剖析
CPU每次从主内存读取数据比较慢,而现代的CPU通常涉及多级缓存,CPU读主内存
按照空间局部性原则加载 局部快到缓存中。
为什么会产生可见性的原因
因为我们CPU读取主内存共享变量的数据时候,效率是非常低,所以对每个CPU设置
对应的高速缓存 L1、L2、L3 缓存我们共享变量主内存中的副本。
相当于每个CPU对应共享变量的副本,副本与副本之间可能会存在一个数据不一致性的问题。
比如线程线程B修改的某个副本值,线程A的副本可能不可见。导致可见性问题。
CPU的摩尔定律
https://baike.baidu.com/item/%E6%91%A9%E5%B0%94%E5%AE%9A%E5%BE%8B/350634?fr=aladdin
基本每隔18个月,可能CPU的性能会提高一倍。
JMM内存模型
Java内存模型定义的是一种抽象的概念,定义屏蔽java程序对不同的操作系统的内存访问差异。
主内存:
存放我们共享变量的数据
工作内存:
每个CPU对共享变量(主内存)的副本。堆+方法区
JMM八大同步规范
(1)lock(锁定):作用于 主内存的变量,把一个变量标记为一条线程独占状态
(2)unlock(解锁):作用于 主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
(3)read(读取):作用于 主内存的变量,把一个变量值从主内存传输到线程的 工作内存中,以便随后的load动作使用
(4)load(载入):作用于 工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
(5)use(使用):作用于 工作内存的变量,把工作内存中的一个变量值传递给执行引擎
(6)assign(赋值):作用于 工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
(7)store(存储):作用于 工作内存的变量,把工作内存中的一个变量的值传送到 主内存中,以便随后的write的操作
(8)write(写入):作用于 工作内存的变量,它把store操作从工作内存中的一个变量的值传送到 主内存的变量中
Volatile汇编lock指令
- 将当前处理器缓存行数据立刻写入主内存中。
- 写的操作会触发总线嗅探机制,同步更新主内存的值。
Java汇编指令查看
E:\java8\jdk\jre\bin\server 放入 hsdis-amd64.dll
首先需要将jar包
|
-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*Mayikt.* |
|
0x0000000002ae6277: lock addl $0x0,(%rsp) ;*putstatic FLAG ; - com.mayikt.Mayikt::[email protected] (line 24) |
Volatile的底层实现原理
通过汇编lock前缀指令触发底层锁的机制
锁的机制两种:总线锁/MESI缓存一致性协议
主要帮助我们解决多个不同cpu之间三级缓存之间数据同步
总线锁
当一个cpu(线程)访问到我们主内存中的数据时候,往总线总发出一个Lock锁的信号,其他的线程不能够对该主内存做任何操作,变为阻塞状态。该模式,存在非常大的缺陷,就是将并行的程序,变为串行,没有真正发挥出cpu多核的好处。
MESI协议
1.M 修改 (Modified) 这行数据有效,数据被修改了,和主内存中的数据不一致,数据只存在于本Cache中。
2.E 独享、互斥 (Exclusive) 这行数据有效,数据和主内存中的数据一致,数据只存在于本Cache中。
3.S 共享 (Shared) 这行数据有效,数据和主内存中的数据一致,数据存在于很多Cache中。
4.I 无效 (Invalid) 这行数据无效。
E:独享:当只有一个cpu线程的情况下,cpu副本数据与主内存数据如果
保持一致的情况下,则该cpu状态为E状态 独享。
S:共享:在多个cpu线程的情况了下,每个cpu副本之间数据如果保持一致
的情况下,则当前cpu状态为S
M:如果当前cpu副本数据如果与主内存中的数据不一致的情况下,则当前cpu状态
为M
I: 总线嗅探机制发现 状态为m的情况下,则会将该cpu改为i状态 无效
该cpu缓存主动获取主内存的数据同步更新。
总线:维护解决cpu高速缓存副本数据之间一致性问题。
如果状态是M的情况下,则使用嗅探机制通知其他的CPU工作内存副本状态为I无效状态,则 刷新主内存数据到本地中,从而多核cpu数据的一致性。
每一行代码都有它的涵义,多问一句为什么;别怕,理清思路,一切代码都是数据的流动和转化,耐心一点,慢慢积累!一起加油!!!