synchronized、volatile、cas 是分层协作的三类机制:synchronized 保障互斥与原子性,volatile 确保可见性与禁止重排序,cas 提供无锁原子更新;三者在 dcl 单例、原子类、锁优化中协同使用。

synchronized、volatile、CAS 并不是互相替代的关系,而是针对不同并发问题分层协作的三类机制:synchronized 解决互斥与原子性,volatile 保障可见性与禁止重排序,CAS 提供无锁的原子更新能力。它们常在同一个并发场景中配合使用,比如 DCL 单例、原子类、锁优化等。
一、各司其职:核心能力边界要分清
理解协同的前提是明确分工:
- synchronized:提供互斥锁 + 内存屏障,进入时强制读主内存(可见性),退出时强制写回主内存(可见性 + 原子性),还能阻塞等待、可重入、自动释放。但它开销大、不可中断、不支持超时。
- volatile:仅保证单次读/写的可见性 + 禁止指令重排序(对变量本身读写加内存屏障),但不保证复合操作的原子性(如 count++ 仍是三步,volatile 无法保护)。
- CAS(Compare-And-Swap):基于硬件指令(如 x86 的 cmpxchg)实现无锁的原子条件更新,配合 volatile 变量使用——volatile 保证每次读取的是最新值,CAS 保证更新动作本身不可分割。
二、典型协同场景:DCL 单例模式
双重检查锁定(Double-Checked Locking)是三者协作的经典案例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用 volatile 修饰 instance 字段,防止 new Singleton() 过程被重排序(避免线程看到未构造完成的对象);
- 外层 if 判断(非同步)利用 volatile 的可见性快速判断是否已初始化,减少锁竞争;
- 内层 synchronized 块确保初始化过程互斥执行一次,而 CAS 在这里虽未显式出现,但 AtomicReference 的 lazySet/CAS 实现底层正是它的延伸;
- 整个结构本质是:volatile 快速读 + synchronized 保原子 + (隐含)CAS 思想支撑无锁优化路径。
三、原子类(如 AtomicInteger):volatile + CAS 的标准组合
java.util.concurrent.atomic 包下的所有类,都是 volatile 和 CAS 协同工作的“教科书级封装”:
- 内部字段(如 value)用 volatile 声明,确保 get() 总能读到最新值;
- incrementAndGet()、compareAndSet() 等方法底层调用 Unsafe.compareAndSwapInt,即 CAS 操作;
- CAS 失败时通常自旋重试(如 safeCount 示例),而 volatile 保证每次重试前都能拿到当前最新值,避免“基于过期快照比较”;
- 没有用 synchronized,所以无锁、无上下文切换,适合高并发读多写少场景。
四、锁优化中的隐性协同:偏向锁 → 轻量级锁 → 重量级锁
synchronized 自身的锁升级机制,也暗含了与 volatile 和 CAS 的底层联动:
- 偏向锁阶段:通过 CAS 修改对象头的 Thread ID 字段,尝试将锁“绑定”到首个访问线程;
- 轻量级锁阶段:用 CAS 尝试将对象头替换为指向栈中锁记录的指针,失败则说明存在竞争,触发锁膨胀;
- 整个过程依赖 volatile 相关的内存语义(如对象头字段的可见性)和 CAS 的原子性,JVM 层面把锁的获取/释放编译为一系列带内存屏障的 CAS 指令;
- 也就是说,现代 synchronized 的高效,正是建立在 volatile 内存语义 + 底层 CAS 指令的坚实基础之上。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










