Version: Next

JMM——Java Memory Model

请谈谈对Volatile的理解

Volatiole是JVM提供的轻量级synchronized同步机制

  1. 保证可见性
  2. 不保证原子性
  3. 禁止指令重排

JMM——Java Memory Model | Java内存模型

  • 不存在,是一种概念,约定

JMM约定

MESI缓存一致性协议

以下提到的内存皆是逻辑概念,不存在对应的真实物理结构,与JVM的运行时内存也没关系

  • 一个线程想要操作主内存中的数据时,并不会直接操作主内存
  • 将主内存中的数据复制一份到自己的线程本地内存中
  • 对线程本地内存中的数据进行操作

线程解锁前

当线程解锁前,必须将本地内存中已经修改的数据,刷回主内存


线程加锁前

当线加锁前,必须读取主内存中的最新值到线程的本地内存中


加锁、解锁一致性

加锁和解锁,操作的是同一把锁

8个方法

  • 高速缓存:即线程本地内存

image-20200629182926768

  • 读:read -> load 顺序执行
  • 写:store -> write 顺序执行
  • JMM 只要求上述两个操作必须按顺讯执行,而没有保证必须是连续执行
  • read和load之间 , 以及store和write之间,可以插入其他方法

若两个线程同时操作主内存中的某个资源flag,当线程B修改其值为false,并将主内存中的flag刷新为false时,线程A本地内存中的flag仍为true,它一直在flag为true的情况下,执行自己的逻辑

  • 线程B所做的修改,线程A不能及时可见

image-20200629184331614

  • 设置两个线程,定义一个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