一段并发代码单测一直正常,上线后偶尔读到旧值,你会如何从 Java 内存模型解释?
我的判断
线上偶尔读到旧值,说明读写之间没有 happens-before;单测时序稳定只是把数据竞争藏住了。
CPU 缓存、编译器优化和指令重排都允许一个线程暂时看不到另一个线程的普通写入。问题不在“主内存多久同步一次”,而在代码没有建立可见性和顺序保证。
我会找到共享字段的所有读写,判断它是单个状态还是一组不变量。单个停止标志可以用 volatile;计数更新用原子类;多个字段必须一起变化时用锁或发布不可变对象。对象构造完成后通过 final 字段、volatile 引用、锁或并发容器安全发布。
例如双重检查单例缺少 volatile 时,引用可能先于构造完成被看到:
private static volatile Client instance;
修复后会用 jcstress 或高并发循环放大竞态,并用代码审查确认所有访问都经过同一同步协议。加 sleep 让用例“稳定”并没有建立 happens-before。