Bohr-L Bohr-L
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

刘博

I'm a slow walker, But I never walk backwards.
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 数据处理与存储类

  • Spring 生态类

  • 缓存问题类

  • 多线程类

  • JVM 类

    • JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的
    • 如何判断对象可以被回收
    • 你知道哪些垃圾收集算法
    • 虚拟机为什么使用元空间替换了永久代
    • 简述 CMS 垃圾收集器的工作流程,它有什么优缺点?
    • 简述一下 JVM 的内存模型
    • 说说堆和栈的区别
    • 简述 Java 的对象结构
    • JVM 中的即时编译器(JIT)如何工作?
    • 什么是内存屏障?JVM 如何使用内存屏障保证指令执行顺序?
      • 如何排查和解决 JVM 内存泄漏问题?有哪些常用的工具和方法?
      • JVM 如何处理异常?try-catch-finally 结构在字节码层面是如何实现的?
    • MySQL 类

    • Java 8 + 特性类

    • 其他技术类

    • 常见面试题
    • JVM 类
    刘博
    2025-12-28
    目录

    什么是内存屏障?JVM 如何使用内存屏障保证指令执行顺序?

    # 1. 内存屏障(Memory Barrier)的定义

    内存屏障是硬件层面的指令,用于解决 “CPU 乱序执行” 和 “缓存一致性” 问题,确保内存操作(读 / 写)的执行顺序和可见性。在多线程场景中,若缺乏内存屏障,CPU 可能为提升效率对指令重排序,导致线程间数据可见性问题(如线程 A 修改的变量,线程 B 无法及时读取到最新值)。

    # 2. 内存屏障的核心作用

    • (1)禁止指令重排序:阻止 CPU 对内存屏障前后的指令进行重排序,确保指令按代码顺序执行;
    • (2)保证内存可见性:强制将 CPU 缓存中的数据刷新到主内存(写屏障),或从主内存重新加载数据到 CPU 缓存(读屏障),确保线程间数据的一致性。

    # 3. 内存屏障的分类(按功能)

    根据作用对象(读 / 写操作),内存屏障分为 4 类:

    屏障类型 作用
    LoadLoad 屏障 确保屏障前的 “读操作”(Load)完成后,再执行屏障后的 “读操作”
    StoreStore 屏障 确保屏障前的 “写操作”(Store)完成并刷新到主内存后,再执行屏障后的 “写操作”
    LoadStore 屏障 确保屏障前的 “读操作” 完成后,再执行屏障后的 “写操作”
    StoreLoad 屏障 确保屏障前的 “写操作” 完成并刷新到主内存后,再执行屏障后的 “读操作”
    • 说明:StoreLoad 屏障功能最全面(可覆盖其他屏障的作用),但性能开销最大,需谨慎使用。

    # 4. JVM 如何使用内存屏障

    JVM 通过在字节码中插入内存屏障,确保 “happen-before 原则”(Java 内存模型的核心,定义线程间操作的可见性规则)的实现,具体场景包括:

    # (1)volatile 关键字的实现

    volatile修饰的变量具有 “可见性” 和 “禁止指令重排序” 特性,JVM 通过插入内存屏障实现:

    • 写操作(volatile 变量赋值):在赋值指令后插入StoreStore 屏障和StoreLoad 屏障:
      • StoreStore 屏障:确保 volatile 变量的写操作完成后,再执行其他普通变量的写操作;
      • StoreLoad 屏障:确保 volatile 变量的写操作刷新到主内存后,再执行后续的读操作(避免其他线程读取到旧值);
    • 读操作(volatile 变量取值):在取值指令前插入LoadLoad 屏障和LoadStore 屏障:
      • LoadLoad 屏障:确保 volatile 变量的读操作完成后,再执行其他普通变量的读操作;
      • LoadStore 屏障:确保 volatile 变量的读操作完成后,再执行其他普通变量的写操作。
    # (2)synchronized 关键字的实现

    synchronized的 “锁释放” 和 “锁获取” 过程隐含内存屏障:

    • 锁释放(退出同步块):JVM 在锁释放位置插入StoreStore 屏障和StoreLoad 屏障,确保同步块内的写操作全部刷新到主内存,其他线程获取锁后可读取到最新值;
    • 锁获取(进入同步块):JVM 在锁获取位置插入LoadLoad 屏障和LoadStore 屏障,确保线程获取锁后,从主内存重新加载变量值,避免使用缓存中的旧值。
    # (3)final 关键字的实现

    final修饰的变量具有 “不可变” 特性(初始化后无法修改),JVM 通过内存屏障确保final变量的初始化可见性:

    • 在final变量初始化完成后、构造函数返回前,插入StoreStore 屏障,确保final变量的写操作完成后,再执行构造函数的其他写操作(避免其他线程看到未初始化完成的final变量)。

    上次更新: 12/30/2025
    JVM 中的即时编译器(JIT)如何工作?
    如何排查和解决 JVM 内存泄漏问题?有哪些常用的工具和方法?

    ← JVM 中的即时编译器(JIT)如何工作? 如何排查和解决 JVM 内存泄漏问题?有哪些常用的工具和方法?→

    最近更新
    01
    CPU 使用率较高排查和解决
    12-29
    02
    JVM OOM 问题如何排查和解决
    12-29
    03
    接口防刷怎么实现?
    12-29
    更多文章>
    Theme by Vdoing | Copyright © 2025-2026 Bohr-L's note
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式