1. volatile
volatile 是 Java 提供的一种轻量级同步机制,主要有两个作用:
保证变量的 可见性:
当一个线程修改了 volatile 变量,其他线程能够立即看到最新的值。
禁止指令重排序:
在 volatile 变量的读写操作前后,JVM 会插入内存屏障,避免指令重排带来的问题。
但是要注意,volatile 不保证原子性,例如 count++ 这种复合操作在多线程下仍然是不安全的。
2、2. CAS(Compare And Swap)
CAS 是一种无锁的原子操作,底层依赖于 CPU 的 cmpxchg 指令来实现。它的逻辑是:
比较某个变量当前的值是否等于预期值(Expected)。
如果相等,就更新为新值(Update)。
如果不相等,说明被其他线程修改过,CAS 操作失败,需要重试。
CAS 的优点:
不需要加锁,线程之间不会阻塞,效率高。
CAS 的缺点:
可能出现 ABA 问题:一个变量从 A → B → A,CAS 检查时发现值还是 A,就会误以为没有变化,导致问题。自旋开销大:CAS 失败会一直自旋重试,如果竞争激烈,会浪费 CPU。只能保证一个变量的原子操作:如果要同时操作多个变量,需要加锁或使用 AtomicReference 等方案。
3、ABA问题
ABA 是 CAS 的典型问题,场景是:
线程 1 读取到变量值为 A。
线程 2 把变量从 A 改成 B,又从 B 改回 A。
线程 1 进行 CAS 时发现值还是 A,以为没变,其实变量已经被改过。
解决 ABA 的办法:
使用 版本号(时间戳)机制:每次更新时不仅更新值,还更新版本号,比如 AtomicStampedReference。使用 AtomicMarkableReference 等带标记的原子类,帮助检测变量是否被修改过。