Java 内存模型 JMM (Java Memory Model)

  • Post author:
  • Post category:java




Java 内存模型 JMM (Java Memory Model)

要搞懂并发编程必须搞懂 JMM.

JMM 屏蔽了不同操作系统中的内存差异性.定义了线程和主内存之前的抽象关系。

线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存存储了该线程以读/写共享变量的副本。本地内存是 JMM 的一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。

JMM 抽象示意图如下:

在这里插入图片描述

从上图来看,线程A 和 B 操作的共享变量都是本地内存中的副本,如果想要互相看到对方操作之后的共享变量,就需要给本地内存的共享变量副本刷到主内存里面去,同时另一个线程从主内存读取共享变量。

JMM 通过控制主内存与每个线程的本地内存之间的交互,来为 我们提供内存可见性保证。



happens-before 原则

这个有点绕。。。需要好好理解一下。

JSR-133 使用 happens-before 来阐述操作之间的内存可见性。

在 JMM 中 如果操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关系。

与我们密切相关的 happens-before 规则如下:

  • 程序顺序规则

    一个线程里面的每一个操作,happens-before 于该线程中的任意后续操作。

    直白点就是 一个线程里面每一个操作的结果 对于后面的操作都是可见的。

  • 监视器锁规则

    对一个锁的解锁,happens-before 于随后对这个锁的加锁。

    翻译一下 大概是 某个持有锁的线程操作的结果在释放之后, 对获取该锁的线程可见

  • volatile 变量规则

    对一个 volatile 域的写,happens-before 于任意后续对这个 volatile 的读。

    翻译版: 对 volatile 的写,对于后续 读该 volatile 域的线程是可见的。volatile 的 内存语义。

  • 传递性

    如果 A happens-before B ,B happens-before C 那么 A happens-before C



volatile 变量 写 -> 读 的内存语义

volatile 变量自身具有下列特性:

  • 可见性

    对一个 volatile 变量的读,总是能看到(任意线程)对这个volatile 变量最后的写入。

  • 原子性

    对任意单个 volatile 变量的读/写具有原子性,但类似于volatile++这种复合操作不具备原子性。

上面是 volatile 自身的特性,如下是 JDK5之后增强的内存语义。

从JSR-133 开始(JDK5开始),volatile 变量的写 – 读 可以实现线程之间的通信。

从内存语义的角度来看,volatile 的写-读 和 锁的释放-获取有相同的内存效果(参考上面监视器规则)。



volatile 写

当写一个 volatile 的变量时,JMM 会把该线程对应的本地内存中的共享变量值刷新到主内存当中。



volatile 读

当读一个 volatile 变量时,JMM 会把该线程对应的本地内存置为无效,该线程将从主内存中读取共享变量。

在这里插入图片描述



参考资料



版权声明:本文为weixin_39913200原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。