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

Java共享变量可见性疑问:无同步下线程总能读取更新值?

你没理解错,只是踩了“并发可见性的概率陷阱”!

兄弟,我当初刚学Java并发的时候也跟你一样,对着书里的结论做测试,结果每次都能看到变量更新,差点怀疑书是不是写错了😂。其实你对《Java并发编程实战》里的内容理解完全没错——没有同步机制的情况下,JVM完全不保证一个线程的修改能被另一个线程看到,但这可不是说“一定看不到”,而是结果完全不可控,你的测试只是刚好每次都撞上了“能看到”的情况而已。

为什么你的测试会“看起来正常”?

这里有几个常见的原因:

  • CPU缓存的巧合刷新:现代CPU的缓存不是永久保存数据的,当缓存满了、线程被操作系统调度暂停、或者有其他触发缓存同步的操作时,修改的值会被刷回主存,刚好被另一个线程读到。你的测试场景可能太简单,线程执行速度快,缓存还没来得及“留住”旧值就同步了。
  • 隐性的同步操作:如果你的测试代码里有打印(比如System.out.println())、Thread.sleep()或者join()这类操作,其实它们内部都带有同步逻辑,会间接触发内存屏障,强制刷新缓存,让变量值变得可见——只是你没意识到这些操作在帮你做同步而已。
  • 简单场景下的JVM优化:当你的测试只有两个线程做简单的读写时,JVM可能会做一些指令优化,甚至在某些情况下把变量直接缓存在寄存器里的概率很低,导致每次都能读到最新值。但一旦把场景变复杂(比如给线程加大量循环、在多核CPU上跑高并发),你就会发现偶尔会出现读取到旧值的情况。

关键要记住:可见性问题是概率性的

并发编程里的可见性BUG最恶心的地方就是它不是必然出现——测试环境、开发机器可能因为CPU核心少、并发量低,永远碰不到,但到了生产环境的多核高并发场景下,就会突然爆发,而且很难复现和排查。

正确的做法

不管测试看起来多“正常”,只要是多线程共享变量的读写,就必须用合法的同步机制来保证可见性:

  • 用synchronized关键字包裹读写操作
  • 给共享变量加上volatile修饰符(适合单一赋值、没有复合操作的场景)
  • 使用java.util.concurrent包下的原子类(比如AtomicInteger)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:57:00