You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Memory Model 意外行为:求教JSR-133规范中该类合法表现的原理

你所贴的示例是JMM领域的经典测试用例,场景为两个共享变量a、b初始值均为0,存在两个执行线程:

  • 线程1执行操作:a = 1 → x = b
  • 线程2执行操作:b = 1 → y = a

这类运行结果被JSR-133规范允许的核心原因有两个:

1. 合法的指令重排序优化

JMM的设计原则是,只要不改变单线程环境下的程序执行结果,编译器、CPU都可以对指令序列做重排序优化。
对于线程1来说,a=1和x=b两个操作不存在数据依赖,重排序两者的执行顺序不会影响线程1单独运行的结果,因此完全允许被调整为x = b先执行,a = 1后执行;同理线程2的操作也可以被重排序为y = a先执行,b = 1后执行。
这种情况下的执行时序可能为:

  1. 线程1执行x = b,此时b还未被赋值,x取初始值0
  2. 线程2执行y = a,此时a还未被赋值,y取初始值0
  3. 线程1执行a = 1
  4. 线程2执行b = 1
    最终就会出现x=0且y=0的结果。

2. 工作内存与主内存的可见性延迟

就算没有发生指令重排序,JMM定义的内存模型中,每个线程都有独立的工作内存,线程对变量的修改会先写入自己的工作内存,默认不会立即同步到主内存,也不会主动推送更新给其他线程的工作内存。
这种情况下的执行时序可能为:

  1. 线程1执行a = 1,修改仅存在于线程1的工作内存中,未同步到主内存
  2. 线程2执行b = 1,修改仅存在于线程2的工作内存中,未同步到主内存
  3. 线程1执行x = b,从主内存读取b的值,拿到初始值0
  4. 线程2执行y = a,从主内存读取a的值,拿到初始值0
    最终同样会得到x=0且y=0的结果。

JSR-133允许这类行为的根本目的是为编译器、CPU留下足够的优化空间,提升程序的整体运行性能。如果要禁止这类结果出现,只需要给a、b变量加上volatile修饰符,就可以禁用相关指令重排序,同时保证变量修改的跨线程可见性,避免该问题。

内容的提问来源于stack exchange,提问作者Hlib

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 19:54:06