Java 内存模型

为了更好的理解 Java 是如何实现 按需禁用缓存和编译优化 的,我们首先需要对 Java 的内存模型有一个初步的了解。

Java 内存模型主要由以下三部分构成:1 个主内存、n 个线程、n 个工作内存(与线程一一对应),数据就在它们三者之间来回倒腾。那么怎么倒腾呢?靠的是 Java 提供给我们的 8 个原子操作:lockunlockreadloaduseassignstorewrite,其操作流程示意图如下:

在这里插入图片描述
一个变量从主内存拷贝到工作内存,再从工作内存同步回主内存的流程为:

|主内存| -> read -> load -> |工作内存| -> use -> |Java线程| -> assign -> |工作内存| -> store -> write -> |主内存|

Java 内存模型中的 8 个原子操作

  • lock:作用于主内存,把一个变量标识为一个线程独占状态。
  • read:作用于主内存,把一个变量的值从主内存传输到线程工作内存中,供之后的 load 操作使用。
  • load:作用于工作内存,把 read 操作从主内存中得到的变量值放入工作内存的变量副本中。
  • use:作用于工作内存,把工作内存中的一个变量传递给执行引擎,虚拟机遇到使用变量值的字节码指令时会执行。
  • assign:作用于工作内存,把一个从执行引擎得到的值赋给工作内存的变量,虚拟机遇到给变量赋值的字节码指令时会执行。
  • store:作用于工作内存,把工作内存中的一个变量传送到主内存中,供之后的 write 操作使用。
  • write:作用于主内存,把 store 操作从工作内存中得到的变量值存入主内存的变量中。
  • unlock:作用于主内存,释放一个处于锁定状态的变量。

8 个原子操作的执行规则

有关变量拷贝过程的规则

  • 不允许 readloadstorewrite 单独出现
  • 不允许线程丢弃它最近的 assign 操作,即工作内存变化之后必须把该变化同步回主内存中
  • 不允许一个线程在没有 assign 的情况下将工作内存同步回主内存中,也就是说,只有虚拟机遇到变量赋值的字节码时才会将工作内存同步回主内存
  • 新的变量只能从主内存中诞生,即不能在工作内存中使用未被 loadassign 的变量,一个变量在 usestore 前一定先经过了 loadassign

有关加锁的规则

  • 一个变量在同一时刻只允许一个线程对其进行 lock 操作,但是可以被一个线程多次 lock(锁的可重入)
  • 对一个变量进行 lock 操作会清空这个变量在工作内存中的值,然后在执行引擎使用这个变量时,需要通过 assignload 重新对这个变量进行初始化
  • 对一个变量执行 unlock 前,必须将该变量同步回主内存中,即执行 storewrite 操作
  • 一个变量没有被 lock,就不能被 unlock,也不能去 unlock一个被其他线程 lock 的变量

可见性问题 -> 有序性问题

通过上图可以发现,Java 线程只能操作自己的工作内存,其对变量的所有操作(读取、赋值等)都必须在工作内存中进行,不能直接读写主内存中的变量。这就有可能会导致可见性问题:

  • 因为对于主内存中的变量 A,其在不同的线程的工作内存中可能存在不同的副本 A1、A2、A3。
  • 不同线程的 readloadstorewrite 不一定是连续执行的,中间可以插入其他命令。Java 只能保证 readloadstorewrite 的执行对于一个线程而言是连续的,但是并不保证不同线程的 readloadstorewrite 的执行是连续的,如下图:

    假设有两个线程 A 和 B,其中线程 A 在写入共享变量,线程 B 要读取共享变量,我们想让线程 A 先完成写入,线程 B 再完成读取。此时即便我们是按照 “线程 A 写入 -> 线程 B 读取” 的顺序开始执行的,真实的执行顺序也可能是这样的:storeA -> readB -> writeA -> loadB,这将导致线程 B 读取的是变量的旧值,而非线程 A 修改过的新值。也就是说,线程 A 修改变量的执行先于线程 B 操作了,但这个操作对于线程 B 而言依旧是不可见的
    那么如何解决这个问题呢?通过上述的分析可以发现,可见性问题的本身,也是由于不同线程之间的执行顺序得不到保证导致的,因此我们也可以将它的解决和有序性合并,即对 Java 一些指令的操作顺序进行限制,这样既保证了有序性,有解决了可见性。

于是乎,Java 给出了一些命令执行的顺序规范,也就是大名鼎鼎 Happens-Before 规则。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值