JMM-JVM内存模型

Java虚拟机定义了一套自己的内存模型(Java Memory Model)来屏蔽各操作系统之间的内存访问差异,定义了虚拟机内存模型、内存交互操作、内存中变量访问规则和一些其他手段配合,保证程序的原子性、可见性和有序性。

主内存和工作内存

类似于CPU的高速缓存和物理内存,JMM也定义了主内存和工作内存,并规定所有非私有的变量必须存储在主内存中,每条线程有自己的工作内存,保存了变量的副本,线程对变量的读取赋值等,在工作内存中完成。线程之间工作内存不可见,信息的传递通过主内存进行。

内存模型交互操作和规则

八种操作

  1. lock:锁定,将主存中的变量变为线程独占。
  2. unlock:解锁,解除一个锁定变量的线程独占。
  3. read:读取,获取主存中变量的值到工作内存中。
  4. load:载入,将read读取的值赋给工作内存中的变量副本。
  5. use:使用,虚拟机执行获取变量值的指令,执行引擎获取工作内存中对应变量的值。
  6. assgin:赋值,虚拟机获取执行引擎返回的值,赋给工作内存变量。
  7. store:存储,将工作内存中的变量传输到主内存。
  8. write:写入,将store的值赋给主内存中的变量。

基本规则

  1. read/load,store/write不允许单独出现一个被执行,且read在load之前,store在write之前,但并不一定两者连续。
  2. 不允许assgin之后不同步回主内存,不允许线程无故将数据从工作内存同步到主存。
  3. 新的变量创建只能在主内存,不允许在工作内存中直接使用未初始化(load或assign)的变量。
  4. 一个变量只能被一个线程lock,同一个线程可对同一个变量过次lock,解锁需执行相同次数unlock。
  5. 对主存变量进行lock会清空工作内存中的该变量的值,使用需重新load或assgin,进行unlock之前需要把工作内存的值同步回主存。

volatile变量特殊规则

  1. 内存模型保证了变量使用之前从主内存刷新一次,变量改变之后同步到主内存一次。
  2. 处理器为了提高执行效率会在保证单线程执行结果正确的前提下,优化指令的执行顺序,volatile可以通过插入内存屏障的方式,禁止指令重排序。

long和double的特殊原则

由于long和double是64位,内存模型允许虚拟机把对应的读写操作划分位两次32操作完成,所有多线程并发读写时,可能会获取到值的一半的情况,但是现在的商用虚拟机都做了处理,把读写操作当作原子的。

先行发生原则

  1. 程序次序规则:同一个线程内,按照代码控制流的顺序,写于前面的优先于后边的执行。
  2. 管程锁定规则:一个监视器锁,unlock优先于后边同一个锁lock操作。
  3. volatile变量规则:volatile变量写操作优先于后边这个变量的读操作。
  4. 传递性:操作A先于操作B,操作B先于操作C,则操作A先于操作C。

Java内存模型的特征

  1. 原子性

内存模型保证了8个基本操作的原子性,需要扩大原子性操作的范围,需要通过提供的lock和unlock操作,Java代码中提供了关键字synchronized,实际通过字节码指令monitorenter和monitorexit来实现。

  1. 可见性

    变量发生了改变对于其他线程时及时可见的,volatile关键字保证了变量的获取和写入及时的跟主内存同步;
    由于unlock操作必须将变量同步会主内存,所以synchronized也能保证可见性;关键字final修饰的字段初始化完成后,构造器没有把“this”的引用传递出去,那么在其他线程就能看见final字段值。

  2. 有序性

Java程序的有序性可以看为,同一线程内部程序表现串行执行,不同线程观察,程序执行是无序的,即指令重排序和内存之间同步的延迟,volatile本身具有指令重排序,synchronized同一时刻只能有一个线程lock,决定了持有同一个锁的两个代码块必须串行执行。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值