Atomic 原子类如何保证原子性?
📌 Atomic 原子类如何保证原子性?
1️⃣ 问题背景
在高并发场景中,如果多个线程同时修改一个变量,就会出现线程安全问题,例如:
- 计数器递增丢失更新
- 库存扣减错误
- 状态更新覆盖
传统解决方案是使用 synchronized 或 Lock,但这些方式属于悲观锁机制,性能开销较大。
因此 Java 提供了 Atomic 原子类,用于在低锁甚至无锁情况下实现线程安全。
2️⃣ 核心原理
Atomic 类的核心依赖是 CAS(Compare And Swap)。
CAS 包含三个核心参数:
- 内存值 V
- 预期值 A
- 更新值 B
执行逻辑如下:
否则:不做任何操作,重新尝试
Atomic 类底层依赖 Unsafe 类调用 CPU 指令(如 cmpxchg),实现硬件级别原子性。
3️⃣ 数据结构分析
以 AtomicInteger 为例,其核心结构如下:
- value:volatile 修饰的 int
- Unsafe:用于底层 CAS 操作
- valueOffset:内存偏移量
private static final Unsafe unsafe;
private static final long valueOffset;
关键点:
4️⃣ 算法分析
Atomic 操作本质是一个自旋 + CAS 重试算法:
2. 计算新值 newValue
3. CAS 尝试更新
4. 如果失败则重新循环
该算法属于乐观锁思想,即默认不会发生冲突,只有冲突时才重试。
优点是避免线程阻塞,但缺点是高竞争环境下会导致CPU 自旋浪费。
5️⃣ 执行流程
AtomicInteger.incrementAndGet()
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
流程说明:
核心是无限循环 + CAS 保证最终只有一个线程成功更新。
6️⃣ 实际案例
多线程计数器
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
count.incrementAndGet();
}
};
启动 100 个线程,每个线程执行 1000 次:
如果使用普通 int:
7️⃣ 优缺点分析
优点
- 无锁实现,高性能
- 基于 CPU 指令,执行效率高
- 避免线程阻塞
- 适合低冲突场景
缺点
- 高并发下 CAS 自旋浪费 CPU
- ABA 问题(需要版本号解决)
- 只能保证单变量原子性
8️⃣ 面试常见问题
1. Atomic 为什么是线程安全的?
因为底层依赖 CAS + volatile + CPU 原子指令。
2. CAS 有什么缺点?
ABA 问题 + 自旋消耗 CPU。
3. Atomic 和 synchronized 区别?
| 对比项 | Atomic | synchronized |
|---|---|---|
| 实现方式 | CAS | 锁机制 |
| 性能 | 高 | 较低 |
| 阻塞 | 非阻塞 | 阻塞 |
4. 如何解决 ABA 问题?
使用 AtomicStampedReference(版本号机制)。
9️⃣ 总结
Atomic 原子类的本质:
① 利用 CAS 实现无锁竞争
② 依赖 CPU 指令保证原子性
③ 结合 volatile 保证可见性
核心思想:
乐观锁 + 自旋重试 + 硬件级别原子指令
相关文章
-
从数据结构到算法:RBAC权限系统的完整实现解析
RBAC(Role-Based Access Control,基于角色的访问控制)是企业级权限系统的主流设计模型。 它通过“用户—角色—权限”的映射关系,将复杂的权限管理问题抽象为结构化的数据模型与可计算的访问控制算法。
NEW个对象 2026-06-08
-
Redis持久化机制详解:RDB与AOF原理、实现流程与生产实践
Redis持久化机制详解:RDB与AOF原理、实现流程与生产实践
NEW个对象 2026-06-12
-
对外接口安全体系的具体实现思路(可落地架构)
对外接口的实现不能只停留在Controller层,而应该是一个完整的“API网关 + 业务服务 + 安全治理”的分层架构。
NEW个对象 2026-06-08