2025-10-10 16:48

AtomicInteger使用详解

王姐姐

Java后端

(27)

(0)

收藏

1. 什么是 AtomicInteger

AtomicInteger 是 Java 提供的一个 线程安全 的整数包装类,位于 java.util.concurrent.atomic 包下。

它允许你在 不使用 synchronized 的情况下,对整数进行原子操作(如自增、自减、加法、比较交换等),从而避免竞态条件(race condition)。

import java.util.concurrent.atomic.AtomicInteger;

AtomicInteger counter = new AtomicInteger(0);

2. 常用方法详解

2.1. get()set(int newValue)

  • get():获取当前值

  • set(int newValue):设置新值(原子操作)

AtomicInteger ai = new AtomicInteger(5);
System.out.println(ai.get()); // 输出: 5
ai.set(10);
System.out.println(ai.get()); // 输出: 10

等价于 volatile 变量的读写,保证可见性。

2.2. incrementAndGet()getAndIncrement()

这两个是最常用的 自增 方法。

方法

含义

返回值

incrementAndGet()

先 +1,再返回

新值

getAndIncrement()

先返回,再 +1

旧值

AtomicInteger ai = new AtomicInteger(5);

int a = ai.incrementAndGet(); // 先加1 → 6,再返回
System.out.println(a); // 6
System.out.println(ai.get()); // 6

int b = ai.getAndIncrement(); // 先返回6,再加1 → 7
System.out.println(b); // 6
System.out.println(ai.get()); // 7

类比

  • ++iincrementAndGet()

  • i++getAndIncrement()

推荐用于计数器、ID 生成等场景。

2.3. decrementAndGet()getAndDecrement()

同理,这是 自减 操作。

AtomicInteger ai = new AtomicInteger(5);

int a = ai.decrementAndGet(); // 4
int b = ai.getAndDecrement(); // 先返回4,再变3

2.4. addAndGet(int delta)getAndAdd(int delta)

加一个指定值

AtomicInteger ai = new AtomicInteger(10);

int a = ai.addAndGet(5);  // 15
int b = ai.getAndAdd(3);  // 返回15,然后变成18

适用于需要加减任意数值的场景。

2.5. compareAndSet(int expect, int update)

这是最核心的方法!基于 CAS(Compare-And-Swap) 实现。

如果当前值等于 expect,就把它更新为 update,并返回 true;否则返回 false

AtomicInteger ai = new AtomicInteger(10);

boolean success = ai.compareAndSet(10, 20);
System.out.println(success); // true,值变为20

boolean failed = ai.compareAndSet(10, 30);
System.out.println(failed);  // false,因为当前值是20,不是10

应用:实现无锁算法、状态机、乐观锁等。

2.6. getAndUpdate(IntUnaryOperator updateFunction)

Java 8 引入的新方法:以函数式方式更新值

AtomicInteger ai = new AtomicInteger(10);

// 当前值乘以2
ai.getAndUpdate(x -> x * 2);
System.out.println(ai.get()); // 20

等价于:

int oldValue = ai.get();
while (!ai.compareAndSet(oldValue, oldValue * 2)) {
    oldValue = ai.get();
}

但更简洁!

2.7. getAndAccumulate(int x, IntBinaryOperator accumulator)

使用二元操作符累积值。

AtomicInteger ai = new AtomicInteger(5);

// 相当于 ai += 3
ai.getAndAccumulate(3, (current, input) -> current + input);
System.out.println(ai.get()); // 8

也可以做其他操作,比如取最大值:

ai.getAndAccumulate(10, Integer::max); // 取当前值和10的最大值

2.8. accumulateAndGet(...)updateAndGet(...)

与上面类似,但 先更新,再返回

AtomicInteger ai = new AtomicInteger(5);
int result = ai.accumulateAndGet(3, (a, b) -> a + b);
// 先计算 5+3=8,再设置,最后返回8
System.out.println(result); // 8

3. 底层原理:CAS + volatile

AtomicInteger 的线程安全性来自于两个核心技术:

技术

作用

CAS(Compare-And-Swap)

保证“比较并交换”是一个原子操作,由 CPU 指令支持(如 x86 的 CMPXCHG

volatile

保证变量的修改对所有线程立即可见(内存可见性)

它内部结构简化如下:

private volatile int value;
private static final long valueOffset = unsafe.objectFieldOffset(...);

public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
  • valuevolatile 的,保证可见性

  • unsafe 调用底层 CAS 指令,保证原子性

4. 使用场景

场景

示例

计数器

页面访问量、请求计数

ID 生成器

内存中生成唯一 ID(如你之前的 idGenerator

状态标志

AtomicBoolean 更合适,但 AtomicInteger 也可用于多状态

限流/信号量

简单的并发控制

无锁算法

构建高性能数据结构

5. 注意事项

5.1. 不要依赖“中间状态”

虽然单个操作是原子的,但多个操作组合不是。

错误写法:

if (ai.get() < 10) {
    ai.incrementAndGet(); // ❌ 在 get 和 increment 之间可能被其他线程修改
}

正确做法:使用 compareAndSet 或同步块。

5.2. 高竞争下可能自旋过度

在大量线程竞争时,CAS 失败会重试(自旋),消耗 CPU。

建议:

  • 低并发:用 AtomicInteger

  • 高并发:考虑 LongAdder

5.3. 初始值很重要

AtomicInteger counter = new AtomicInteger(0); // 清晰表达意图

6. 对比:AtomicInteger vs synchronized vs LongAdder

方式

性能

适用场景

synchronized

较低,阻塞

复杂逻辑,临界区大

AtomicInteger

高,无锁

单一变量原子操作

LongAdder

极高,分段累加

高并发计数(如监控系统)

LongAdderAtomicLong/AtomicInteger 的升级版,用于高并发累加场景。

LongAdder adder = new LongAdder();
adder.increment();
long sum = adder.sum(); // 获取总和

7. 完整示例:线程安全的计数器

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AtomicCounter {
    private static AtomicInteger counter = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 1000; i++) {
            executor.submit(() -> {
                counter.incrementAndGet();
            });
        }

        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);

        System.out.println("最终计数: " + counter.get()); // 一定是 1000
    }
}

即使 10 个线程并发操作,结果也准确无误。

8. 总结

方法

用途

get() / set()

读写值

incrementAndGet()

先加后取(推荐)

getAndIncrement()

先取后加

compareAndSet(expect, update)

CAS 核心,实现乐观锁

getAndUpdate(func)

函数式更新

addAndGet(delta)

加指定值

0条评论

点击登录参与评论