登录
首页 >  文章 >  java教程

Java内存模型解决了什么问题?核心解析

时间:2026-01-02 11:39:51 115浏览 收藏

一分耕耘,一分收获!既然都打开这篇《Java内存模型解决了哪些问题?核心解析》,就坚持看下去,学下去吧!本文主要会给大家讲到等等知识点,如果大家对本文有好的建议或者看到有不足之处,非常欢迎大家积极提出!在后续文章我会继续更新文章相关的内容,希望对大家都有所帮助!

JMM专治多线程下变量读写不可见、重排序致逻辑错乱、原子性被破坏三类问题:通过happens-before规则、volatile、synchronized等机制保障可见性、有序性与原子性。

Java里JMM解决了哪些问题_Java内存模型核心说明

Java内存模型(JMM)不是为了解决“内存不够用”或“GC频繁”这类问题,它专治多线程环境下**变量读写不可见、重排序导致逻辑错乱、以及原子性被破坏**这三类根本性问题。

为什么多个线程读不到彼此写的值?

这是JMM最常被感知到的问题:一个线程更新了sharedFlag = true,另一个线程却一直看到false。根本原因在于,线程可能从自己的工作内存(CPU缓存或寄存器)读取该变量,而没有及时从主内存同步最新值。

解决方式依赖JMM定义的“happens-before”规则和具体同步机制:

  • volatile字段写操作对其他线程立即可见(禁止重排序 + 强制刷新主内存)
  • 进入synchronized块前,会清空本地工作内存;退出时强制把变更刷回主内存
  • 线程启动(Thread.start())、终止(Thread.join())也建立happens-before关系

为什么代码顺序没变,执行结果却像“乱序”?

JMM允许编译器、JIT、CPU在不改变单线程语义的前提下重排序指令。例如下面这段代码:

int a = 0;
boolean ready = false;

// 线程1
a = 1;
ready = true;

// 线程2
if (ready) {
    System.out.println(a); // 可能输出0!
}

看似a = 1ready = true之前,但JMM允许将这两句重排序(尤其在无同步时)。线程2看到ready == true,却读到旧的a == 0

关键约束点:

  • volatile写之前的所有操作,不能被重排序到该写之后
  • volatile读之后的所有操作,不能被重排序到该读之前
  • synchronized块内语句受锁边界限制,不会逸出到外侧

long/double赋值为什么不是原子的?

在32位JVM上,longdouble是64位宽,可能被拆成两次32位写操作。若无同步,一个线程可能读到“半个新值+半个旧值”的中间态(如高位是旧值、低位是新值)。

JMM明确要求:volatile longvolatile double的读写必须是原子的;普通long/double则不保证——这不是bug,而是JMM的设计选择,用以平衡性能与可实现性。

实践中更推荐:

  • 始终用volatile修饰共享的long/double字段
  • 或封装进AtomicLong/AtomicLongFieldUpdater等原子类
  • 避免依赖非volatile 64位变量的“天然原子性”

真正难的是把happens-before规则映射到具体代码结构里——比如final字段的初始化安全发布、ConcurrentHashMap内部如何用volatile+CAS绕过锁、甚至Lambda闭包捕获变量时的内存可见性边界。这些细节一旦漏掉,问题只会在高并发压测时爆发,且极难复现。

今天关于《Java内存模型解决了什么问题?核心解析》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

前往漫画官网入口并下载 ➜
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>