Version: Next
JMM——Java Memory Model
请谈谈对
Volatile
的理解
Volatiole是JVM提供的轻量级synchronized同步机制
- 保证可见性
- 不保证原子性
- 禁止指令重排
JMM——Java Memory Model | Java内存模型
- 不存在,是一种概念,约定
JMM约定
MESI缓存一致性协议
以下提到的内存皆是逻辑概念,不存在对应的真实物理结构,与JVM的运行时内存也没关系
- 一个线程想要操作主内存中的数据时,并不会直接操作主内存
- 将主内存中的数据复制一份到自己的线程本地内存中
- 对线程本地内存中的数据进行操作
线程解锁前
当线程解锁前,必须将本地内存中已经修改的数据,刷回主内存
线程加锁前
当线加锁前,必须读取主内存中的最新值到线程的本地内存中
加锁、解锁一致性
加锁和解锁,操作的是同一把锁
8个方法
- 高速缓存:即线程本地内存
- 读:read -> load 顺序执行
- 写:store -> write 顺序执行
- JMM 只要求上述两个操作必须按顺讯执行,而没有保证必须是连续执行
- read和load之间 , 以及store和write之间,可以插入其他方法
若两个线程同时操作主内存中的某个资源flag,当线程B修改其值为false,并将主内存中的flag刷新为false时,线程A本地内存中的flag仍为true,它一直在flag为true的情况下,执行自己的逻辑
- 线程B所做的修改,线程A不能及时可见
例
- 设置两个线程,定义一个int num = 0
- 第一个线程:如果num == 0就跑循环
- 第二个线程:睡1秒,让第一个线程先跑起来,然后修改num为1,然后把num的值打印出来
public class Demo {
private static int num = 0;
public static void main(String[] args) throws InterruptedException { // 主线程
new Thread(() -> { // 线程1
while (num == 0) {
}
}).start();
// 睡2秒,让上面自定义的线程先跑起来
TimeUnit.SECONDS.sleep(2);
// 在主线程修改num的值
num = 1;
// 输出num
System.out.println(num);
}
}
分析:
- 按道理来说,第二个线程修改了num的值,并把num的值打印出来了,等于1
- 此时num不再等于0了,第一个线程的循环应当跳出,然后运行会发现1被打印出来了,而线程1还在执行自己的循环,这就是线程2对num的操作,线程1是不可见的,线程1不知道主内存的值已经被修改
info
要解决这个问题,需要使用Volatile