速通–Java内存模型(JMM)
什么是JMM
- JMM就是Java 内存模型(java memory model)
- 同一段代码在不同的系统上会出现不同的问题。但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。
八种内存交互操作
- lock,把变量标识为线程独占的状态
- read,把变量值从主存内传输到工作内存中
- load,把read的值放入工作内存的变量副本当中去
- use,当虚拟机遇到需要执行该变量的字节码时会执行该操作
- assign,当虚拟机改变变量的值时会执行该操作
- store,assign发生后,将新值传回主内存更新
- unlock,释放变量,使得其能够被其他线程锁定
- read后必然执行load,assign后必然执行store
- 对变量进行lock操作时,会清空所有工作内存中该变量的值
- 对变量进行unlock操作之前,必须先把该变量同步回主内存
内存屏障
- 分为四类,LoadLoad屏障,StoreStore屏障,LoadStore屏障,StoreLoad屏障
- 拿LoadLoad屏障举例来说,即在第二个load发生前,第一个load应该先执行完毕,其他屏障以此类推。