速通–Java内存模型(JMM)

什么是JMM

  • JMM就是Java 内存模型(java memory model)
  • 同一段代码在不同的系统上会出现不同的问题。但JMM屏蔽掉了操作系统的差异性,使得我们编写的Java程序能够在各个平台上都能达到一致的并发效果。
  • 其中所有变量都储存在主内存中,但不包括局部变量和方法参数。
  • 线程对变量的操作都在各自的工作内存中进行,且不能直接读写主内存中的变量。当然了,不同线程之间也无法访问各自工作内存的变量。其间的传递需要通过主存来进行。

Java lsi模型 java jmm模型_Java

JMM的三个特征

原子性

  • 原子性指的是一个事务的操作要么不间断地全部被执行,要么一个也没执行。在这里指的是一个线程操作时不会被其他线程干扰。只有一步操作能保证原子性。
  • 我们来看看下面代码是否能保证原子性
int i = 5;
int j = i;
i++;
  • 第一句为赋值操作,只有一步,必然为原子性操作
  • 第二和第三局都需要先读取i的值再进行下一步操作,为两步操作,所以不能保证原子性

可见性

  • 可见性指的是当一个线程修改变量的值,其他线程也能知道该变量被修改了,其中是利用volatile来实现的。
  • 当变量被volatile修饰时,这个变量修改后会立即刷新到主内存,所以其他线程读取该变量时就能得知其已经被修改了。

有序性

  • 我们在Java中使用synchronized或者volatile保证多线程之间操作的有序性。
  • volatile是使用内存屏障达到禁止指令重排序
假设
a = 1
b = 2 
c = 3
d = 4
e = 5
其中只有c被volatile修饰,则ab赋值操作语句和de赋值操作语句不能调换位置,但ab语句的执行顺序可以改变,cd同理
  • synchronized的原理则为:一个线程lock之后,必须unlock,才能有其他线程重新lock。

八种内存交互操作

Java lsi模型 java jmm模型_Java lsi模型_02

  • lock,把变量标识为线程独占的状态
  • read,把变量值从主存内传输到工作内存中
  • load,把read的值放入工作内存的变量副本当中去
  • use,当虚拟机遇到需要执行该变量的字节码时会执行该操作
  • assign,当虚拟机改变变量的值时会执行该操作
  • store,assign发生后,将新值传回主内存更新
  • unlock,释放变量,使得其能够被其他线程锁定
  • read后必然执行load,assign后必然执行store
  • 对变量进行lock操作时,会清空所有工作内存中该变量的值
  • 对变量进行unlock操作之前,必须先把该变量同步回主内存

内存屏障

  • 分为四类,LoadLoad屏障,StoreStore屏障,LoadStore屏障,StoreLoad屏障
  • 拿LoadLoad屏障举例来说,即在第二个load发生前,第一个load应该先执行完毕,其他屏障以此类推。