• 面试官: JVM是怎么解决多线程new对象分配空间的
  • 我:

    JVM 通过 TLAB(线程本地分配缓冲区)+ CAS + Eden 区分配,实现多线程高效创建对象,尽量避免锁竞争。

    1. 什么是 TLAB
      • 每一个线程都有一小块“私有内存”在 Eden 里。线程创建对象优先在自己的 TLAB 里分配
        1
        2
        3
        Eden 区:

        [ TLAB-线程1 ][ TLAB-线程2 ][ TLAB-线程3 ][ 公共区域 ]
    2. TLAB 不够了怎么办
      • 重新申请一个 TLAB(优先)
      • 分配到共享 Eden(用 CAS)
  • 面试官: 你刚才说线程私有的对象会分配到栈中,什么对象是线程私有的?
  • 我:
    1. 满足以上三个条件的就是线程私有的对象:

      • 只在方法内部使用
      • 没有返回
      • 没有赋值给共享变量
    2. 逃逸分析判断对象分配

      • 什么是逃逸分析:逃逸分析(Escape Analysis)是 JVM 在运行时分析对象是否被外部访问的一种优化手段,用来判断对象的作用范围,从而决定是否进行栈上分配、锁消除、标量替换等优化。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    对象创建

    是否逃逸?

    ┌───────────────┬───────────────┐
    │ 不逃逸 │ 逃逸 │
    ├───────────────┼───────────────┤
    │ 线程私有 ✔ │ 非线程私有 ❌ │
    │ 可栈上分配 │ 必须在堆 │
    │ 可锁消除 │ 可能需要加锁 │
    └───────────────┴───────────────┘
  • 面试官: 介绍一下JMM
  • 我:

    JMM 是 Java 定义的多线程内存访问规则,用来保证共享变量在多线程下的正确性

    1. JMM解决了线程的三大问题
      • 可见性问题 (线程 A 修改变量,线程 B 看不到)
      • 原子性问题 (i++ 不是原子性)
      • 有序性问题(指令重排)
    2. JMM 的核心模型
      • 主内存(Main Memory) → 所有线程共享
      • 工作内存(Working Memory) → 每个线程私有
    3. 变量访问流程
      主内存 → 工作内存 → 线程操作 → 写回主内存

      ❗ 线程不能直接操作主内存
      ❗ 必须通过工作内存

    4. 什么是 happens-before
      happens-before 是用来判断“线程之间操作是否可见、是否有序”的规则
      • 例如 A happens-before B
        1. A 一定先执行
        2. A 的结果对 B 可见
  • 面试官: volatile 可以保证原子性吗?
  • 我:

    volatile 不保证原子性
    ✅ 只保证可见性 + 有序性

    保证原子性需要加锁!!!