Sunday面试指南

Java 内存模型 JMM 是什么?happens-before 等于代码先执行吗?

下面是一段教学用的模拟面试。

🧑‍💻 面试官: Java 内存模型是什么?happens-before 怎么理解?

🙋‍♂️ 我: 就是前面的操作先执行,后面的操作能看到它的结果。

🧑‍💻 面试官: 线程 A 先写了配置,过了一秒线程 B 才读。没有同步,B 就一定能读到吗?

🙋‍♂️ 我: 不能只看两个线程实际执行的时间。

🧑‍💻 面试官: 那你怎样证明配置已经被正确发布?请指出中间的同步关系。

这道题不是让你猜哪个线程先跑,而是让你说明:跨线程的数据,靠什么规则保证对方能看到。

面试速答(60 秒版)

JMM 是 Java 内存模型,它规定多线程程序里,对共享变量的读写允许出现哪些结果,以及同步操作提供什么保证。

happens-before 是判断可见性和顺序的重要关系。如果 A happens-before B,A 的相关效果就应当对 B 可见。它不是两个事件在钟表上谁先发生的记录。

例如,在同一个线程里,前面的操作 happens-before 后面的操作;释放一个监视器锁,happens-before 后续对同一个锁的获取;volatile 写,happens-before 后续对同一个变量的读。关系还可以传递。

实际分析时,要把数据写入、发布动作、接收动作和数据读取连起来。只加 sleep、只看日志时间,不能替代同步。

happens-before 不是钟表排序

图:happens-before 不是钟表排序。

知识点详解:配置写完了,对方为什么还不能随便读?

“已经发生”与“有保证”是两回事

假设线程 A 创建一份配置,写入共享字段,再把 ready 标志设成 true。线程 B 等 ready 变成 true,然后读取配置。

如果这些都是普通字段,两个线程没有建立合适的同步关系,那么“机器上试了几次都正常”并不能证明它正确。我们不能把某一次恰好看到的结果,当成内存模型给出的保证。

这里也不必把“工作内存、主内存”画成每个变量必经的物理运输路线。JMM 是语言层面的规则,真实硬件缓存和编译器优化更复杂。

正确的解释,要连起四个动作

仍然用这个发布配置的例子,假设 ready 是 volatile,且这次读取观察到了用于发布配置的那个 true;初始化后也没有其他线程无保护地修改配置。

关系可以这样说清楚:

  1. A 先写配置,再写 ready,同一线程的程序顺序建立第一段关系。
  2. A 对 ready 的 volatile 写,与 B 后续的相应 volatile 读建立同步关系。
  3. B 先读 ready,再使用配置,程序顺序建立第三段关系。
  4. 根据传递性,前面的配置写入与后面的配置读取连了起来。

重点不是“volatile 会把所有东西神奇地刷一遍”,而是哪些操作之间建立了哪条关系。具体规则可以核对 JLS 第 17 章。

反过来,如果 B 根本没有读取这个发布标志,或者读到的是另一次发布的值,就不能把上面的推理原样套上去。

把配置写入和读取连起来

图:把配置写入和读取连起来。

锁为什么也能完成这件事?

如果 A 在同一个锁的保护下写配置,B 后续获取这个锁再读取,也可以通过解锁、加锁关系传递可见性。

不过必须是同一个监视器。两个名字都叫 lock、实际却不是同一个对象的锁,并不能给这两次访问搭桥。

另外,可见性不是全部问题。如果几个线程同时对一个计数器做“读、加一、写回”,能看到旧值不代表组合操作就是原子的。这个例子仍然需要正确的互斥或原子操作。

为什么日志和 sleep 不能用来证明?

sleep 主要改变调度机会,不给共享字段自动建立需要的同步关系。打印日志可能改变时序,甚至让问题暂时不容易出现,但它不是这段业务数据的设计依据。

正确的排查顺序是先检查共享变量与同步设计,再用压力测试、诊断工具寻找问题。测试没有复现,不等于不存在数据竞争。

本文针对 Java 的规则,不用 TS、Python 的线程 API 冒充 JMM 实现。

面试官继续追问

happens-before 要求底层指令完全不重排吗?

不要求所有底层执行都按源码机械排列。实现可以优化,但不能让程序观察到违反相关保证的结果。

能背出规则,为什么还会写错?

因为知道“volatile 写到读”不等于检查了谁读哪个值、后续对象是否继续被修改。规则需要落到具体的数据流上。

面试速记卡

  • JMM:规定共享变量读写与同步的可观察行为。
  • happens-before:可见性和顺序关系,不是钟表先后。
  • 推理:程序顺序 → 同步关系 → 程序顺序。
  • 传递性:把发布前写入与接收后读取连起来。
  • 边界:可见性不等于复合操作原子性,sleep 不替代同步。

公司面试真题

真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。

  • 美团 · 开发(含 AI 项目追问) · 原帖未明确批次

    Java 内存模型怎样工作?(题意整理)

    美团面经 ↗
    原帖发布于 2025-09-09

  • 美团 · Java后端 · 实习

    JMM 的原理是什么?(题意整理)

    4.21美团Java实习一二面面经 ↗
    面试记录为 2020-04-21、2020-04-24;原帖编辑于 2020-11-14

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历