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

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

相关推荐
颜酱3 分钟前
03 | 实现节点1 — 抽取关键词
前端·人工智能·后端
风吹心凉4 分钟前
python3基础2026.7.22
开发语言·python
qq_4523962312 分钟前
第五篇:《接口与错误处理:Go 的哲学》
开发语言·后端·golang
Escalating_xu26 分钟前
C++可变参数模板与引用折叠精讲
开发语言·c++
wuyk55531 分钟前
59.嵌入式C语言高级宏定义实战:多行宏、字符串化与符号拼接
c语言·开发语言·stm32·单片机·嵌入式硬件·物联网·51单片机
程序猿乐锅33 分钟前
【数据结构与算法 | 第六篇】力扣1109,1094差分数组
java·算法·leetcode
神奇小汤圆34 分钟前
SpringBoot + 虚拟线程,简直鸟枪换大炮~
后端
云泽80837 分钟前
Visual Studio 2026 新手保姆级教程:环境搭建、界面优化与编译器配置详解
开发语言·c++·c·开发工具·visual studio
yeflx44 分钟前
速腾Airy雷达使用记录
java·服务器·网络
掘金一周1 小时前
想问问掘友们:AI 时代,资深开发的核心价值到底在哪里?| 沸点周刊 7.23
前端·人工智能·后端