JAVA内存模型(JMM)
2022-11-22 15:11:38 1 举报
JAVA内存模型(JMM)
作者其他创作
大纲/内容
volatile原则
unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
local var2(基本类型)
不允许访问
传递性原则
保证load1的读取操作在load2及后续读取操作之前执行
Store1; StoreStore; Store2
local var1(引用类型)
成员变量
不管怎么重排序(单线程)程序的执行结果不能被改变
(主内存的变量拷贝)
Lock
load
存在共享数据区域和私有数据区域
synchronizedLock
Load1; LoadLoad; Load2
可见性
工作内存
保证被volatile修饰的共享变量对所有线程总数可见的,也就是当一个线程修改了一个被volatile修饰共享变量的值,新值总是可以被其他线程立即得知
如何实现禁止指令重排优化
线程,工作内存,主内存工作交互图(基于JMM规范)
use
同步规则
保证Store2及其后的写操作执行前,保证Load1的读操作
1、不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中
StoreStore
Java虚拟机提供的轻量级的同步机制
5、如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
happens-before 原则
2、指令级并行重排序
有序性
lock
volatile
load1; LoadStore; Store2
解锁操作必然发生在后续同一个锁的加锁之前
lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态
线程启动原则
不同点
不会对存在数据依赖关系的操作做重排序
store
use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎
4、最终执行的指令序列
LoadLoad
别称:内存栅栏,是一条CPU指令
3、内存系统重排序
6、对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)
JMM如何解决原子性&可见性&有序性
Store1; StoreLoad; Load2
程序顺序原则
不需要通过任何手段就能够得到保证的有序性
local var1(基本类型)
volatile变量正是通过内存屏障实现其在内存中的语义,即可见性和禁止重排优化
JMM 控制
write
1、编译器优化重排序
lfence,是一种Load Barrier 读屏障
Lock前缀,Lock不是一种内存屏障,但是它能完成类似内存屏障的功能
保证某些变量的内存可见性
A先于B ,B先于C 那么A必然先于C
两个作用
指令示例
为什么需要重排
线程A
volatile保证可见性,当共享变量被volatile修饰后,它会保证修改的值立马被其他线程看到,即修改的值立即更新到主存中,当其他线程需要读取时,它会去内存中读取新值
静态变量
read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
volatile变量的写,先发生于读,这保证了volatile变量的可见性
含义
影响有序性
遵循
volatilesynchronizedLock
围绕
其他数据
read
说明
线程2
store(保存):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作
可见性问题
有序性问题
原子性
3、一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现
源代码
从源码到最终执行的指令序列示意图
即如果线程A在执行线程B的start方法之前修改了共享变量的值,那么当线程B执行start方法时,线程A对共享变量的修改对线程B可见
屏障类型
JAVA内存模型
编译器runtime处理器
unlock
保证Load2及其后的读操作执行前,保证Store1的写操作
JMM描述的是一组规则,通过这组规则控制程序中各个变量在共享数据区域和私有数据区域的访问方式
基本类型的读写是具有原子性的
synchronized
保证Store2及其后的写操作执行前,保证Store1的写操作
线程1
数据的八大原子性
方法2的帧栈:
也可以保证可见性,因为synchronized和Lock 保证任一时刻只有一个线程能访问共享资源,并在其释放锁之前将修改的变量刷新到内存中
对象终结规则对象的构造函数执行,结束先于finalize()方法
JMM
指令重排序
volatile可以保证一定的有序性,sychronized和Lock也可以保证有序性
局部变量
保证特定操作的执行顺序
内存屏障((Memory Barrier)
内容
load(装载):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
即在一个线程内必须保证语义串行性,也就是说按照代码顺序执行
原子性问题
VM能根据处理器特性(CPU多级缓存系统、多核处理器等)适当的对机器指令进行重排序,使机器指令能更符合CPU的执行特性,最大限度的发挥机器性能。
assgin(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
2、一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或者assign)的变量。即就是对一个变量实施use和store操作之前,必须先自行assign和load操作。
assign
禁止指令重排序优化
锁原则
JVM
4、如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量之前需要重新执行load或assign操作初始化变量的值。
java语言规范规定JVM线程内部维持顺序化语义。即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码顺序不一致,此过程叫指令的重排序
共享变量
as-if-serial语义
主要存储当前方法的所有本地变量信息
LoadStore
常量
方法1的帧栈:
线程终止原则
硬件提供一系列内存屏障
当一个线程修改了某个共享变量的值,其他线程是否能够马上得知这个修改的值
对线程 interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测线程是否中断
write(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中
线程中断原则
线程的所有操作先于线程的终结,Thread.join()方法的作用是等待当前执行的线程终止
具有一些先天性有序性
共享类信息
主内存
通过synchronized和Lock实现原子性,保证任一时刻只有一个线程访问该代码块
StoreLoad
volatile禁止指令重排序
JVM提供了四种内存屏障指令
0 条评论
下一页