JDK14中AbstractQueuedSynchronizer使用setPrevRelaxed如何保证内存可见性
AQS 中 setPrevRelaxed 的 node.prev 可见性保障逻辑
这个设计是并发场景下的典型性能优化,可见性保障可以从两个层面解释:
- 调用
setPrevRelaxed时节点还未被多线程共享
方法注释明确标注for off-queue assignment,意思是该方法仅在节点还未被加入同步队列时调用。对应enq入队逻辑中,新创建的节点是线程私有的,先通过setPrevRelaxed给新节点设置prev指向旧尾节点,此时其他线程没有任何途径能访问到这个新节点,自然不需要额外的可见性保证,用普通写的开销更低。 - 节点发布操作自带可见性兜底
给新节点设置完prev后,才会通过compareAndSetTail操作尝试将 AQS 的tail字段更新为新节点,这个 CAS 操作本身自带 volatile 写语义。根据 Java 内存模型的 Happens-Before 规则:volatile 写之前的所有操作(包括这里的prev普通写),都会对后续能读取到该 volatile 写结果的线程可见。
其他线程要访问这个新节点的prev字段,必然要先通过 volatile 读拿到 AQS 的tail引用才能遍历到该节点,此时prev字段的更新对该线程是完全可见的。
内容的提问来源于stack exchange,提问作者Ander
相关产品推荐
相关产品推荐

