04 - volatile 原理分析
作者:互联网
什么是 Volatile
能够保证线程可见性,当一个线程修改主内存中共享变量时,能够保证对另外一个线程可见性,
但是注意他不能够保证共享变量的原子性问题。
Volatile的特性
可见性
能够保证线程可见性,当一个线程修改主内存中共享变量时,能够保证对另外一个线程可见性,
但是注意他不能够保证共享变量的原子性问题。
顺序性
程序执行程序按照代码的先后顺序执行。
原子性
即一个操作或者多个操作 要么全部执行并且执行的过程,要么失败。
Volatile可见性
public class Mayikt extends Thread {
/**
* lock 锁 汇编的指令 强制修改值,立马刷新主内存中 另外线程立马可见刷新主内存数据
*/
private static volatile boolean FLAG = true;
@Override
public void run() {
// 这个 FLAG 是 CPU 里面高速缓存里的数据,不是主内存中共享变量的数据
while (FLAG) {
System.out.println("子线程");
}
}
public static void main(String[] args) throws InterruptedException {
new Mayikt().start();
Thread.sleep(1000);
FLAG = false;
System.out.println("主线程退出");
}
}
为什么会产生可见性的原因
CPU每次从主内存读取数据比较慢,而现代的CPU通常涉及多级缓存,CPU读主内存。
按照空间局部性原则加载 局部快到缓存中。
因为我们CPU读取主内存共享变量的数据时候,效率是非常低,所以对每个CPU设置 对应的高速缓存 L1、L2、L3 缓存我们共享变量主内存中的副本。
相当于每个CPU对应共享变量的副本,副本与副本之间可能会存在一个数据不一致性的问题。
比如线程线程B修改的某个副本值,线程A的副本可能不可见。导致可见性问题。
JMM内存模型
Java内存模型定义的是一种抽象的概念,定义屏蔽java程序对不同的操作系统的内存访问差异。
主内存:存放我们共享变量的数据
工作内存:每个CPU对共享变量(主内存)的副本。堆+方法区
JMM八大同步规范
-
lock(锁定):作用于 主内存的变量,把一个变量标记为一条线程独占状态
-
unlock(解锁):作用于 主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
-
read(读取):作用于 主内存的变量,把一个变量值从主内存传输到线程的 工作内存中,以便随后的load动作使用
-
load(载入):作用于 工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
-
use(使用):作用于 工作内存的变量,把工作内存中的一个变量值传递给执行引擎
-
assign(赋值):作用于 工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
-
store(存储):作用于 工作内存的变量,把工作内存中的一个变量的值传送到 主内存中,以便随后的write的操作
-
write(写入):作用于 工作内存的变量,它把store操作从工作内存中的一个变量的值传送到 主内存的变量中
Volatile汇编lock指令
-
将当前处理器缓存行数据立刻写入主内存中。
-
写的操作会触发总线嗅探机制,同步更新主内存的值。
Volatile的底层实现原理
通过汇编lock前缀指令触发底层锁(总线)的机制
主要帮助我们解决多个不同cpu之间三级缓存之间数据同步
总线
总线:工作内存访问到主内存数据的时候,都会经过我们的总线。
总线主要能够帮助我们解决:多个不同CPU核之间的工作内存副本数据一致性问题。
总线分为总线索和MESI协议
总线锁
当一个cpu(线程)访问到我们主内存中的数据时候,往总线总发出一个Lock锁的信号,其他的线程不能够对该主内存做任何操作,变为阻塞状态。该模式,存在非常大的缺陷,就是将并行的程序,变为串行,没有真正发挥出cpu多核的好处。
MESI协议
-
M 修改 (Modified) 这行数据有效,数据被修改了,和主内存中的数据不一致,数据只存在于本Cache中。
-
E 独享、互斥 (Exclusive) 这行数据有效,数据和主内存中的数据一致,数据只存在于本Cache中。
-
S 共享 (Shared) 这行数据有效,数据和主内存中的数据一致,数据存在于很多Cache中。
-
I 无效 (Invalid) 这行数据无效。
E:独享:当只有一个cpu线程的情况下,cpu副本数据与主内存数据如果保持一致的情况下,则该cpu状态为E状态 独享。
S:共享:在多个cpu线程的情况了下,每个cpu副本之间数据如果保持一致的情况下,则当前cpu状态为S
M:如果当前cpu副本数据如果与主内存中的数据不一致的情况下,则当前cpu状态为M
I: 总线嗅探机制发现 状态为m的情况下,则会将该cpu改为i状态 无效
该cpu缓存主动获取主内存的数据同步更新。
如果状态是M的情况下,则使用嗅探机制通知其他的CPU工作内存副本状态为I无效状态,则 刷新主内存数据到本地中,从而多核cpu数据的一致性。
标签:volatile,变量,04,副本,线程,内存,原理,数据,cpu 来源: https://www.cnblogs.com/YeQuShangHun/p/16595853.html