Java并发原生工具:原子类 (Atomic Classes)

核心速览

java.util.concurrent.atomic包提供无锁、高性能的线程安全工具,基于 CAS (Compare-And-Swap)​ 与 VarHandle(JDK 9+)实现,避免 synchronized阻塞开销,适用于单变量原子更新。

核心原理:通过 CPU CAS 指令(比较并交换)保证原子性;JDK 9 起推荐 VarHandle(替代 Unsafe),JDK 21 原子类全面基于 VarHandle。

关键分类:

  • 基本类型:AtomicInteger(32位)、AtomicLong(64位)、AtomicBoolean(仅布尔值,无算术操作);
  • 引用类型:AtomicReference(对象引用)、AtomicStampedReference(带版本号解决ABA)、AtomicMarkableReference(带标记简化ABA);
  • 数组类型:AtomicIntegerArray等(原子更新数组单个元素);
  • 高并发优化:LongAdder/DoubleAdder(分段累加,高并发计数性能远超 AtomicLong)。

原子类是 java.util.concurrent.atomic 包下的一组高性能、无锁(lock-free)线程安全工具,用于在多线程环境下安全地更新单个变量,无需使用 synchronizedReentrantLock。它们是实现无锁并发编程的核心组件。

核心原理:CAS 与 VarHandle

  • count++ 的非原子性

    该操作在字节码层面包含三步:读取 → 加1 → 写回。在多线程下,这些步骤可能交错执行,导致更新丢失。

  • 传统方案:加锁

    使用 synchronized 可以保证安全,但会带来上下文切换、竞争和阻塞的开销。

  • 原子类方案:CAS

    原子类通过 CPU 的 CAS (Compare-And-Swap) 指令实现原子操作,避免了锁的开销,在低到中等竞争场景下性能显著优于锁。其早期实现依赖 sun.misc.Unsafe,但从 JDK 9 起,官方推荐使用 java.lang.invoke.VarHandle 作为底层标准 API。

  • VarHandle 的核心方法
    VarHandle 提供了更安全、可移植的底层访问能力,支持以下操作:

    • compareAndSet(expected, value)
    • getAndSet(value)
    • getAndAdd(delta)
    • getAcquire() / setRelease()
  • JDK 21 及以后

    所有原子类(如 AtomicInteger)内部已全面基于 VarHandle 实现。


原子类分类与用法

1、基本类型原子类

用于原子化地更新 booleanintlong 等基本类型。

说明 常用方法
AtomicBoolean 原子布尔值 get(), set(newValue), compareAndSet(expect, update), getAndAdd(delta)
AtomicInteger 原子整型 (32位) 同上
AtomicLong 原子长整型 (64位) 同上

2、引用类型原子类

用于原子化地更新对象引用,解决对象引用的并发问题。

说明 示例
AtomicReference<T> 原子引用 AtomicReference<String> ref = new AtomicReference<>("hello"); ref.compareAndSet("hello", "world");
AtomicMarkableReference<T> 带 boolean 标记的引用 用于解决 ABA 问题的简化方案。
AtomicStampedReference<T> 带 int "戳"的引用 通过版本号解决更通用的 ABA 问题。

3、数组类型原子类

保证对数组中单个元素的操作是原子的,而非整个数组。

说明 注意
AtomicIntegerArray 原子整型数组 操作指定索引的元素。
AtomicLongArray 原子长整型数组 同上。
AtomicReferenceArray<T> 原子引用数组 同上。

4、高并发优化类 (Java 8+)

LongAdderDoubleAdder 专为高并发写场景(如计数器)设计。在激烈竞争下,AtomicLong 因 CAS 失败重试频繁而性能下降,而 LongAdder 通过分段累加(cell 机制)大幅降低了竞争,性能更优。


常见误区

  1. 误区 1:atomic.get() + 1 是原子操作

    java

    // 错误!非原子操作

    int newVal = atomic.get() + 1;

    atomic.set(newVal);

    必须使用 incrementAndGet()getAndIncrement() 等原子方法。

  2. 误区 2:compareAndSet 一定会成功

    在高竞争或 ABA 问题下可能失败,通常需要配合循环重试逻辑。LongAdder 在高并发计数场景下是更优选择。


最佳实践

  1. 优先使用 LongAdder / DoubleAdder:作为计数器,尤其在写并发高的场景。
  2. 避免复合操作 :如 if (atomic.get() < 100) atomic.increment();,这需要外部同步来保证原子性。
  3. 勿用于复杂状态机 :对于复杂的状态流转,应使用 synchronizedjava.util.concurrent 中的高级工具(如 Phaser, StampedLock)。
  4. 使用标准 API :在 JDK 9+ 中,应使用 VarHandle 而非 sun.misc.Unsafe

一键三连,让我的信心像气球一样膨胀!

相关推荐
摇滚侠4 小时前
Java,举例说明,函数式接口,函数式接口实现类,通过匿名内部类实现函数式接口,通过 Lambda 表达式实现函数式接口,演变的过程
java·开发语言·python
阿里嘎多学长4 小时前
2026-02-03 GitHub 热点项目精选
开发语言·程序员·github·代码托管
Tony Bai4 小时前
“Go 2,请不要发生!”:如果 Go 变成了“缝合怪”,你还会爱它吗?
开发语言·后端·golang
打工的小王4 小时前
java并发编程(七)ReentrantReadWriteLock
java·开发语言
lang201509284 小时前
Java并发革命:JSR-133深度解析
java·开发语言
禹凕4 小时前
Python编程——进阶知识(面向对象编程OOP)
开发语言·python
abluckyboy4 小时前
基于 Java Socket 实现多人聊天室系统(附完整源码)
java·开发语言
Re.不晚4 小时前
JAVA进阶之路——数据结构之线性表(顺序表、链表)
java·数据结构·链表
毅炼4 小时前
Java 基础常见问题总结(3)
java·开发语言
m0_748229994 小时前
PHP简易聊天室开发指南
开发语言·php