atomicinteger 通过 cpu 的 cas 指令实现无锁线程安全,incrementandget() 先增后返新值,getandincrement() 先返旧值再增,非原子组合操作(如 get+set)不安全,且不可绕过原子方法直接修改内部 volatile 字段。

AtomicInteger 为什么能避免锁但又保证线程安全
因为它的核心操作(如 incrementAndGet())底层调用的是 CPU 的 CAS(Compare-And-Swap)指令,由硬件直接保证原子性,不需要 JVM 层面的 synchronized 或显式锁。只要没有其他线程在你读取-比较-写入的瞬间修改同一变量,操作就成功;失败则重试——整个过程无阻塞、无上下文切换开销。
注意:CAS 不是万能的。当竞争极其激烈(比如上千线程同时争抢一个 AtomicInteger),可能反复失败重试,导致 CPU 使用率飙升,此时反而不如用 LongAdder。
incrementAndGet() 和 getAndIncrement() 的行为差异很关键
这两个方法都原子递增,但返回值不同,选错会导致逻辑 bug:
-
incrementAndGet()先加 1,再返回新值(类似++i) -
getAndIncrement()先返回旧值,再加 1(类似i++)
例如统计请求序号时,若想让第一个请求拿到 1,应使用 incrementAndGet();若要记录“处理前的计数值”,才用 getAndIncrement()。
不能用普通赋值或复合操作替代原子方法
下面这些写法都是线程不安全的,即使变量声明为 AtomicInteger:
// ❌ 错误:非原子操作,i.get() 和 i.set(...) 之间可能被其他线程插入 int current = i.get(); i.set(current + 1); // ❌ 错误:看似简洁,实则先 get 再 set,中间断层 i.set(i.get() + 1); // ✅ 正确:一步到位,由 CAS 保障 i.incrementAndGet();
AtomicInteger 的线程安全只体现在它提供的原子方法上,对它的任意“读-改-写”组合,必须封装成单个原子调用,否则等于白用。
初始值和 reset 场景下容易忽略 volatile 语义
AtomicInteger 内部用 volatile int value 存储,所以构造时传入的初始值会立即对所有线程可见;但如果你手动用 set(0) 重置,同样依赖 volatile 写的内存语义——这点没问题。
真正容易出问题的是:有人试图通过反射或 Unsafe 修改其内部 value 字段,绕过原子方法。这不仅破坏原子性,还可能因绕过 volatile 写,导致其他线程永远看不到更新。
别为了“省一次方法调用”去碰内部字段,set() 和 lazySet() 已经足够轻量且语义明确。










