news 2026/4/21 18:25:02

并发编程(二):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/21 18:24:23

基于微信小程序的设备报修系统PHP_nodejs_vue+uniapp

文章目录微信小程序设备报修系统技术方案前端技术实现后端服务架构核心功能模块系统特色优势系统设计与实现的思路主要技术与实现手段源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;微信小程序设备报修系统技术方案 该系统采用前后端分离…

作者头像 李华
网站建设 2026/4/21 18:25:01

档案馆参观预约系统 微信小程序PHP_nodejs_vue+uniapp

文章目录档案馆参观预约系统技术架构功能模块设计关键技术实现数据安全与性能优化用户体验设计系统设计与实现的思路主要技术与实现手段源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;档案馆参观预约系统技术架构 该系统采用前后端分离架…

作者头像 李华
网站建设 2026/4/21 18:25:00

Keil uVision5调试环境搭建:手把手操作指南

从零搭建Keil uVision5调试环境&#xff1a;工程师的实战手记最近接手一个基于STM32F4的工业控制项目&#xff0c;客户要求在两周内完成Bootloader开发和通信协议联调。时间紧、任务重&#xff0c;第一件事就是——先把调试环境搭稳。别小看这一步。我见过太多团队因为“下载失…

作者头像 李华
网站建设 2026/4/19 20:48:37

IAR下载在工业控制中的应用:手把手教程(从零实现)

深入工业控制核心&#xff1a;IAR 下载的底层逻辑与实战精要在现代工厂的自动化产线上&#xff0c;一台 PLC 正精确控制着机械臂的每一次抓取动作&#xff1b;在风力发电机组的塔筒深处&#xff0c;一个嵌入式控制器正实时监测转速并调整桨距角。这些看似静默运行的设备背后&am…

作者头像 李华
网站建设 2026/4/20 12:05:19

项目调试阶段使用逻辑分析仪定位I2C HID代码10问题

用逻辑分析仪“破案”&#xff1a;一次IC HID设备报错代码10的深度排查实录最近在调试一款基于IC接口的HID触摸板时&#xff0c;设备管理器里又出现了那个熟悉的黄色感叹号——“此设备无法启动&#xff08;代码10&#xff09;”。这已经是第三块PCB改版后依然复现的问题了。虽…

作者头像 李华
网站建设 2026/4/18 10:46:05

Keil MDK中实现CAN总线控制的深度剖析

在Keil MDK中构建稳定可靠的CAN通信系统&#xff1a;从原理到实战的完整路径你有没有遇到过这样的场景&#xff1f;设备之间明明接好了线&#xff0c;代码也烧录进去了&#xff0c;可就是收不到CAN报文。查了波特率、确认了终端电阻、甚至换了收发器芯片&#xff0c;问题依旧存…

作者头像 李华