Java volatile语义、JMM保证与final字段多线程可见性问询
问题解答
是的,当number字段被声明为final后,任何看到data引用不为null的线程,都能保证看到number的正确值(也就是42)。这背后是Java内存模型(JMM)的两条关键规则在协同作用:
1. Volatile变量的读写屏障机制
data是被volatile修饰的变量,根据JMM的规则:
- 对
volatile变量的写操作会触发内存屏障,确保写操作之前的所有内存变更(包括构造SomeData对象、给final字段number赋值的操作)都被刷新到主内存; - 后续对这个
volatile变量的读操作也会触发内存屏障,强制从主内存加载最新值,同时保证读操作之后的代码能看到写操作之前的所有内存变更。
简单来说,线程A调用initialize()给data赋值的动作,会和线程B读取data的动作之间建立明确的happens-before关系——线程A在赋值data前完成的所有操作(包括把number初始化为42),线程B在看到data不为null时都能完全感知到。
2. Final字段的安全初始化规则
当number是final字段时,只要SomeData的构造函数没有逸出this引用(也就是构造函数里没有把当前对象的引用传递给其他线程),那么构造函数中对final字段的赋值操作,会happens-before其他线程看到这个对象的引用。
你的代码里,SomeData的构造函数只是单纯给number赋值,没有任何逸出this的行为,所以这个初始化过程是绝对安全的。结合volatile的屏障效果,双重保障下,线程看到data不为null时,必然能看到number的正确值42。
对比一下如果number不是final的情况:这时即使data是volatile,也无法保证线程看到data时number已经被正确赋值(因为构造函数里的普通字段赋值可能被指令重排,和data的赋值顺序颠倒),但final字段刚好解决了这个指令重排的问题。
内容的提问来源于stack exchange,提问作者alxg2112
相关产品推荐
相关产品推荐

