news 2026/4/15 13:45:16

并发编程(二):Java原子类(Atomic Classes)全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
并发编程(二):Java原子类(Atomic Classes)全解析

文章目录

    • 1. 核心原理:CAS (Compare-And-Swap)
      • 什么是 CAS
      • Java 中的 Unsafe 类
    • 2. 原子类家族谱系
    • 3. 实战演练:AtomicInteger
      • 场景:多线程计数器
        • 错误示范:普通 int
        • 正确示范:AtomicInteger
      • 源码剖析:getAndIncrement
    • 5. 高性能利器:LongAdder (JDK 8+)
      • 设计思想:分段锁(空间换时间)
      • AtomicLong vs LongAdder 性能对比示意
        • 代码示例

在多线程并发编程的浩瀚宇宙中,线程安全始终是核心议题。当我们需要对一个变量进行简单的累加操作时,volatile关键字虽然能保证可见性,却无法保证原子性;而synchronized锁虽然强大,但在高并发场景下往往伴随着沉重的上下文切换开销。

这时,Java原子类(Atomic Classes)应运而生。它们位于java.util.concurrent.atomic包下,利用底层硬件的 CAS 机制,以一种无锁(Lock-Free)的高效方式,解决了并发场景下的原子性问题。


1. 核心原理:CAS (Compare-And-Swap)

原子类的魔法源自于CAS。它是一条 CPU 并发原语。

什么是 CAS

关于CAS的原理可以看这篇:https://blog.csdn.net/Tracycoder/article/details/156860586?spm=1011.2415.3001.10575&sharefrom=mp_manage_link

Java 中的 Unsafe 类

Java 无法直接访问底层操作系统,而是通过sun.misc.Unsafe类来操作内存。原子类内部正是调用了 Unsafe 的compareAndSwap系列方法。


2. 原子类家族谱系

JDK 提供了丰富的原子类,主要可以分为以下四类:

分类包含类描述
基本类型AtomicInteger,AtomicLong,AtomicBoolean直接更新基本类型数据。
数组类型AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray原子更新数组中的某个元素。
引用类型AtomicReference,AtomicStampedReference,AtomicMarkableReference原子更新对象引用,解决ABA问题。
对象属性AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUpdater原子更新对象的某个字段。

3. 实战演练:AtomicInteger

AtomicInteger是最常用的原子类。让我们对比一下使用intAtomicInteger在多线程下的表现。

场景:多线程计数器

假设有 100 个线程,每个线程对计数器累加 1000 次。

错误示范:普通 int
publicclassUnsafeCounter{privatestaticintcount=0;publicstaticvoidmain(String[]args)throwsInterruptedException{Thread[]threads=newThread[100];for(inti=0;i<100;i++){threads[i]=newThread(()->{for(intj=0;j<1000;j++){count++;// 非原子操作:读 -> 改 -> 写}});threads[i].start();}for(Threadt:threads)t.join();// 预期结果:100000,实际结果通常小于 100000System.out.println("Final Count (Unsafe): "+count);}}
正确示范:AtomicInteger
importjava.util.concurrent.atomic.AtomicInteger;publicclassSafeCounter{// 使用原子类privatestaticAtomicIntegeratomicCount=newAtomicInteger(0);publicstaticvoidmain(String[]args)throwsInterruptedException{Thread[]threads=newThread[100];for(inti=0;i<100;i++){threads[i]=newThread(()->{for(intj=0;j<1000;j++){// 相当于 i++,但在硬件层面保证原子性atomicCount.getAndIncrement();}});threads[i].start();}for(Threadt:threads)t.join();// 结果始终为 100000System.out.println("Final Count (Atomic): "+atomicCount.get());}}

源码剖析:getAndIncrement

AtomicIntegergetAndIncrement是如何实现的?

// JDK 8 源码片段publicfinalintgetAndIncrement(){// this: 当前对象// valueOffset: value 字段在内存中的偏移量// 1: 增加的值returnunsafe.getAndAddInt(this,valueOffset,1);}// Unsafe 类中的实现 (模拟)publicfinalintgetAndAddInt(Objecto,longoffset,intdelta){intv;do{// 1. 获取内存中当前的值v=getIntVolatile(o,offset);// 2. 循环尝试 CAS 操作// 如果内存值还是 v,则更新为 v + delta,返回 true 退出循环// 否则(说明被其他线程改了),返回 false,继续循环(自旋)}while(!compareAndSwapInt(o,offset,v,v+delta));returnv;}

5. 高性能利器:LongAdder (JDK 8+)

虽然AtomicLong使用 CAS 保证了原子性,但在超高并发下,大量线程同时竞争更新同一个变量,会导致大量 CAS 失败并自旋,消耗 CPU 资源。

JDK 8 引入了LongAdder

设计思想:分段锁(空间换时间)

LongAdder内部维护了一个base变量和一个Cell[]数组。

  • 无竞争时:直接更新base
  • 有竞争时:线程被哈希映射到Cell数组的某个槽位,对该槽位的值进行 CAS 更新。
  • 获取最终结果时:sum = base + sum(Cell[])

AtomicLong vs LongAdder 性能对比示意

LongAdder

CAS

Hash

Hash

Hash

Thread A

Base

Thread B

Cell 1

Thread C

Cell 2

Thread D

AtomicLong

CAS 竞争

CAS 竞争

CAS 竞争

CAS 竞争

Thread 1

Value

Thread 2

Thread 3

Thread 4

代码示例
importjava.util.concurrent.atomic.LongAdder;publicclassLongAdderDemo{publicstaticvoidmain(String[]args){LongAdderadder=newLongAdder();// 多个线程同时累加adder.increment();adder.add(10);// 获取总和System.out.println("Sum: "+adder.sum());}}

注意:LongAddersum()方法返回的值只是一个近似准确值(在并发极高时,统计过程中可能有新的累加发生),但在统计计数等场景下完全够用且性能极佳。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/11 13:29:58

结合温升测试验证工业用PCB线宽电流对照表

温升实测揭秘&#xff1a;工业PCB走线到底能扛多大电流&#xff1f;从一个烧断的铜箔说起某天&#xff0c;一位工程师在调试一台工业变频器时发现&#xff0c;设备运行十几分钟后突然停机。检查发现&#xff0c;主板上一条看似“足够宽”的电源走线竟然局部碳化、断裂——而这根…

作者头像 李华
网站建设 2026/4/12 8:15:21

W5500与STM32结合的看门狗机制设计:操作指南

W5500与STM32协同看门狗设计&#xff1a;从原理到实战的完整指南你有没有遇到过这样的场景&#xff1f;一台部署在工厂角落的工业网关&#xff0c;连续运行了几周后突然“失联”——Ping不通、数据中断&#xff0c;但现场检查却发现设备电源正常&#xff0c;MCU似乎还在跑代码。…

作者头像 李华
网站建设 2026/4/12 10:09:49

Keil5调试STM32硬件断点使用场景解析

硬件断点实战&#xff1a;在Keil5中精准调试STM32的底层秘密你有没有遇到过这样的场景&#xff1f;代码烧进STM32后&#xff0c;运行到一半突然“死机”&#xff0c;串口毫无输出&#xff1b;你想在main()函数前打个断点看看启动流程&#xff0c;却发现断点变成了灰色小圆圈——…

作者头像 李华
网站建设 2026/4/13 22:25:54

延吉推荐烤肉哪家无广

延吉无广烤肉推荐&#xff1a;延炭乳酸菌烤肉在延吉&#xff0c;烤肉是当地美食文化的重要组成部分。众多烤肉店让人眼花缭乱&#xff0c;而延炭乳酸菌烤肉以其独特的健康理念和美味菜品脱颖而出&#xff0c;是一家值得推荐的无广优质烤肉店。招牌菜品&#xff0c;美味健康延炭…

作者头像 李华
网站建设 2026/4/11 21:28:08

8位加法器硬件连接与调试实战案例

从理论到板级&#xff1a;8位加法器硬件实战中的那些“坑”与突破你有没有遇到过这样的情况——明明逻辑设计完全正确&#xff0c;Verilog代码综合无误&#xff0c;仿真波形也完美匹配真值表&#xff0c;可一旦烧进FPGA、接上拨码开关和数码管&#xff0c;输出就开始乱跳&#…

作者头像 李华
网站建设 2026/4/4 2:24:36

Java Web 民宿在线预定平台系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

摘要 随着旅游业的快速发展和互联网技术的普及&#xff0c;民宿在线预定平台逐渐成为游客出行住宿的重要选择。传统的民宿预定方式存在信息不透明、沟通效率低、管理混乱等问题&#xff0c;亟需通过数字化手段优化用户体验和运营效率。民宿在线预定平台通过整合房源信息、在线支…

作者头像 李华