在Java里如何使用Atomic类实现无锁并发_Java原子操作原理说明

胖婷同学_4839

胖婷同学_4839

2026-01-20

529人浏览

原创

AtomicInteger 更轻量因基于CAS指令,避免线程挂起与上下文切换;但高竞争下重试耗CPU,适用于计数器等简单操作,不适用复合逻辑。

在java里如何使用atomic类实现无锁并发_java原子操作原理说明

AtomicInteger 为什么比 synchronized 更轻量

因为 AtomicInteger 底层调用的是 CPU 提供的 CAS(Compare-And-Swap)指令,不涉及操作系统线程挂起/唤醒,避免了锁带来的上下文切换开销。但要注意:CAS 在高竞争下会不断重试,反而可能比锁更耗 CPU。

典型适用场景是计数器、状态标志位这类简单读-改-写操作,比如秒杀库存扣减、请求统计。不适合复合逻辑(如“先读再判断再更新”),那得用 synchronized 或 ReentrantLock。

常见错误是误以为 incrementAndGet() 能替代所有同步场景——它只保证单个原子操作,不保证多个原子操作之间的顺序或可见性组合。

getAndIncrement 和 incrementAndGet 的区别在哪

两者都执行“加 1 并返回旧值”或“加 1 并返回新值”,但语义和返回值不同:

  • getAndIncrement() 返回自增前的值(类似 i++)
  • incrementAndGet() 返回自增后的值(类似 ++i)

性能上无差别,选哪个纯看业务需要。例如生成唯一 ID 时常用 incrementAndGet(),而做轮询索引时可能用 getAndIncrement() 避免额外减 1。

注意:它们都不是“线程安全的 ++ 运算符替代品”——Java 中没有原生的原子 ++ 操作符,必须显式调用这些方法。

javascript-typescript-typescript-scaffold
javascript-typescript-typescript-scaffold

你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型

下载

AtomicReference 用错引用比较会出什么问题

AtomicReference 的 compareAndSet(expected, updated) 是按引用地址比较(==),不是按内容(.equals())。如果传入一个新构造的对象作为 expected,即使字段值相同,也会失败。

常见踩坑点:

  • 用 new String("abc") 作期望值,而当前值是字符串常量池里的 "abc"
  • 在循环中反复 new 对象用于 compareAndSet,导致永远无法匹配
  • 误以为它能自动处理对象内部字段的原子更新(不能,要用 AtomicReferenceFieldUpdater 或 VarHandle)
AtomicReference<string> ref = new AtomicReference("hello");
// ❌ 错误:new String 创建新对象,引用不同
ref.compareAndSet(new String("hello"), "world"); // 返回 false

// ✅ 正确:复用原引用或使用 intern()
ref.compareAndSet("hello", "world"); // 返回 true</string>

AtomicLongArray 在批量计数时怎么避免伪共享

多核 CPU 缓存以 cache line(通常 64 字节)为单位加载数据。AtomicLongArray 的相邻元素若落在同一 cache line,会导致不同线程更新不同下标时相互干扰(false sharing),性能骤降。

解决方式不是换工具,而是结构对齐:

  • 手动 padding:每个 long 后填充 7 个 long,确保每个有效元素独占 cache line(但浪费内存)
  • 用 jdk.internal.vm.annotation.Contended(JDK 8+,需开启 -XX:-RestrictContended)
  • 更实际的做法是:避免高频更新密集下标;或改用分段计数(如 LongAdder,它内部就用了类似 padding 的策略)

LongAdder 比 AtomicLong 更适合高并发累加场景,但它不是“更高级的 AtomicLong”,而是牺牲了实时一致性来换吞吐——它的 sum() 不是强一致的。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

7599

3

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

2023.10.24

6404

49

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

2023.10.24

6404

49

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

3564

5

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

2025.10.17

1952

13

字符串常量的表示方法
字符串常量的表示方法

字符串常量的表示方法:1、使用引号;2、转义字符;3、多行字符串;4、原始字符串;5、字符串连接;6、字符串字面量和对象;7、编码问题。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.12.26

1183

5

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1938

5

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

3204

5

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

2023.10.24

6404

49

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习