面试题:什么是 Java 内存模型(JMM)?

Java 内存模型(Java Memory Model, JMM) 是 Java 虚拟机(JVM)定义的一种规范,用于描述多线程环境下,线程如何与主内存和工作内存交互,以及如何保证线程之间的可见性、有序性和原子性。JMM 是 Java 并发编程的基础,它定义了线程之间的通信规则,确保多线程程序在不同平台上的行为一致。


1. JMM 的核心概念

JMM 主要围绕以下几个核心概念展开:

(1)主内存(Main Memory)

  • 主内存是所有线程共享的内存区域,存储了所有的变量(实例字段、静态字段等)。
  • 主内存是线程通信的桥梁。

(2)工作内存(Working Memory)

  • 每个线程都有自己的工作内存,存储了线程对变量的副本。
  • 线程对变量的所有操作(读取、赋值等)都在工作内存中进行,不能直接操作主内存。

(3)内存间的交互

  • 线程通过以下操作与主内存交互:
    • read:从主内存读取变量到工作内存。
    • load:将读取的变量值放入工作内存的变量副本中。
    • use:线程使用工作内存中的变量值。
    • assign:线程将新的值赋给工作内存中的变量。
    • store:将工作内存中的变量值写回主内存。
    • write:将存储的变量值更新到主内存中。

2. JMM 的三大特性

JMM 的核心目标是解决多线程环境下的 可见性有序性 和 原子性 问题。

(1)可见性(Visibility)

  • 一个线程对共享变量的修改,能够及时被其他线程看到。
  • JMM 通过以下机制保证可见性:
    • volatile 关键字:确保变量的修改对所有线程立即可见。
    • synchronized 关键字:在释放锁之前,将工作内存中的变量刷新到主内存。
    • final 关键字:确保构造器中的赋值操作对其他线程可见。

(2)有序性(Ordering)

  • 程序执行的顺序按照代码的先后顺序执行。
  • JMM 通过以下机制保证有序性:
    • volatile 关键字:禁止指令重排序。
    • synchronized 关键字:确保同一时刻只有一个线程执行同步代码块。
    • happens-before 规则:定义了一系列操作之间的先后顺序。

(3)原子性(Atomicity)

  • 一个操作是不可分割的,要么全部执行成功,要么全部不执行。
  • JMM 通过以下机制保证原子性:
    • synchronized 关键字:确保同步代码块的原子性。
    • 原子类(如 AtomicInteger:通过 CAS 操作保证原子性。

3. happens-before 规则

happens-before 是 JMM 中定义的一种偏序关系,用于描述操作之间的可见性和有序性。以下是常见的 happens-before 规则:

  1. 程序顺序规则:同一线程中的操作,前面的操作 happens-before 后面的操作。
  2. 锁规则:解锁操作 happens-before 后续的加锁操作。
  3. volatile 规则:写 volatile 变量 happens-before 读 volatile 变量。
  4. 传递性规则:如果 A happens-before B,且 B happens-before C,那么 A happens-before C。

4. JMM 与硬件内存模型的关系

  • JMM 是一个抽象的概念,它屏蔽了底层硬件内存模型的差异(如 CPU 缓存、指令重排序等)。
  • JMM 通过定义统一的规则,确保 Java 程序在不同硬件平台上的一致性。

5. 示例

以下是一个简单的示例,展示了 volatile 关键字如何保证可见性:

public class VisibilityExample {
    private volatile boolean flag = false;

    public void writer() {
        flag = true; // 写操作
    }

    public void reader() {
        while (!flag) {
            // 等待 flag 变为 true
        }
        System.out.println("Flag is true");
    }
}

在这个例子中,volatile 确保了 writer() 线程对 flag 的修改对 reader() 线程立即可见。


6. 总结

  • Java 内存模型(JMM) 是 Java 并发编程的基础,定义了多线程环境下线程如何与内存交互。
  • JMM 通过 可见性有序性 和 原子性 三大特性,确保多线程程序的正确性。
  • happens-before 规则是 JMM 的核心,用于描述操作之间的顺序关系。
  • JMM 屏蔽了底层硬件的差异,为 Java 程序提供了统一的内存模型。
THE END
点赞13 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容