AtomicInteger 的 CAS 无锁原理¶
一、问题¶
i++ 是读-改-写三步,多线程下会丢数据。用 synchronized 太重。
二、CAS 是什么¶
Compare And Swap,一条 CPU 指令:
整个操作是原子的(CPU 指令保证)。
三、AtomicInteger.incrementAndGet()¶
U.getAndAddInt 底层:
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset); // 读当前值
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
流程¶
- 读当前值 v。
- 计算新值 v + delta。
- CAS:如果内存里还是 v,就改成 v + delta。
- CAS 失败(被别的线程改了),回到 1 重试(自旋)。
四、为什么无锁¶
没有 synchronized,没有线程阻塞。竞争激烈时自旋空转,但不用 OS 切换线程,性能更高。
五、适用场景¶
- 计数器(点击数、点赞数)。
- 状态机。
- 竞争不激烈(竞争激烈时自旋浪费 CPU)。
CAS 的缺点
- ABA 问题。
- 自旋浪费 CPU。
- 只能保证一个变量的原子性。