结论:三点都认同,尤其“volatile 修饰引用≠元素”——这是最常被误用的地方,我顺着补几个能落地的细节。
一、复现的坑:不要用 -Xint 关闭 JIT 来验证。解释器每次都从主内存读取,那段死循环反而会“跑对”,于是容易让人误判代码没问题。正确做法是用 -XX:+PrintCompilation 查看方法何时被 C2 编译,那才是问题可能出现的时间点。jcstress 也一样,建议加上 -XX:+UnlockDiagnosticVMOptions,重排序结果才能稳定复现。
二、数组元素可见性:JDK9+ 用 MethodHandles.arrayElementVarHandle(int[].class) 的 getAcquire/setRelease,或者直接换 AtomicIntegerArray/AtomicReferenceArray;逐个元素处理老代码不现实,换原子数组最省事。
三、判断标准再补充一条:volatile 不只用于状态标志,它还有个用途是做“发布闸门”:先写若干普通变量,最后写一个 volatile 标志;读侧看到标志置位后,再去读那些普通变量。靠 volatile 写 happens-before 后续读,保证前面所有写入都可见。这其实正是双检锁里那个 volatile 的本质,也是除 final 之外最常用的无锁安全发布方式。
结尾提醒:final 的安全发布只在“构造器内写入且没泄漏 this”时成立——在构造器里注册监听器、启动线程、把 this 传给别的对象,这套保证就没了;而内部类单例之所以稳妥,是因为类初始化由 JVM 加锁保证,跟 final 无关。
正式会员
认证极客






