Java 并发中的原子类

1. 为什么需要原子类

多线程环境下,有个常见问题:

java 复制代码
public class Counter {
    private int count = 0;

    public void increment() {
        count++;
    }
}

count++ 看似一行代码,实际分三步:

  1. 读取 count 的值
  2. 加 1
  3. 写回 count

多线程下可能发生:

复制代码
线程A:读取 count=0
线程B:读取 count=0
线程A:count=1,写回
线程B:count=1,写回   // 线程A的结果被覆盖了

最终 count=1,但实际应该等于 2。

2. 解决办法

synchronized 加锁

java 复制代码
public synchronized void increment() {
    count++;
}

缺点:性能差,每次只能一个线程进入。

原子类

java 复制代码
private AtomicInteger count = new AtomicInteger(0);

public void increment() {
    count.incrementAndGet();
}

一行搞定,性能比 synchronized 高很多。

3. 常用原子类

AtomicInteger

java 复制代码
AtomicInteger count = new AtomicInteger(0);

// 加1
count.incrementAndGet();  // ++i
count.getAndIncrement();  // i++

// 减1
count.decrementAndGet();  // --i
count.getAndDecrement();  // i--

// 加任意值
count.addAndGet(5);

// 获取值
int value = count.get();

// 设置值
count.set(100);

// CAS 操作
count.compareAndSet(100, 200);  // 如果当前值是100,则设置为200

AtomicLong

和 AtomicInteger 用法一样,只是类型不同:

java 复制代码
AtomicLong count = new AtomicLong(0);
count.incrementAndGet();

AtomicBoolean

java 复制代码
AtomicBoolean flag = new AtomicBoolean(false);

// 设为 true
flag.set(true);

// CAS 操作
flag.compareAndSet(false, true);

AtomicReference

用来原子更新对象:

java 复制代码
AtomicReference<User> userRef = new AtomicReference<>();

User user1 = new User("张三", 20);
User user2 = new User("李四", 25);

userRef.set(user1);
userRef.compareAndSet(user1, user2);  // 如果当前是 user1,则改为 user2

4. 数组原子类

java 复制代码
// 数组中某个元素原子操作
AtomicIntegerArray arr = new AtomicIntegerArray(new int[]{1, 2, 3});

arr.getAndAdd(0, 10);  // 第一个元素加10
int value = arr.get(0);  // 获取第一个元素

5. 累加器

jdk8 新增的,比 AtomicInteger 性能更高,专门用于累加场景:

java 复制代码
LongAdder count = new LongAdder();

count.add(1);
count.increment();
long value = count.sum();

内部原理是把一个值拆成多个 Cell,减少竞争。适合高并发场景下的累加。

java 复制代码
// AtomicInteger vs LongAdder
// 低并发:两者差不多
// 高并发:LongAdder 性能更好

6. 实战示例

计数器

java 复制代码
public class PageViewCounter {
    private AtomicInteger count = new AtomicInteger(0);

    public void addView() {
        count.incrementAndGet();
    }

    public int getViews() {
        return count.get();
    }
}

防止重复提交

java 复制代码
public class SubmitService {
    private AtomicBoolean submitting = new AtomicBoolean(false);

    public void submit() {
        // 如果已经在提交中,直接返回
        if (!submitting.compareAndSet(false, true)) {
            return;
        }

        try {
            // 业务逻辑
            doSubmit();
        } finally {
            submitting.set(false);
        }
    }
}

配置更新

java 复制代码
public class ConfigHolder {
    private AtomicReference<Config> configRef = new AtomicReference<>();

    public void updateConfig(Config newConfig) {
        configRef.updateAndGet(old -> newConfig);
    }

    public Config getConfig() {
        return configRef.get();
    }
}

7. 总结

类 用途
AtomicInteger 整数原子操作
AtomicLong 长整数原子操作
AtomicBoolean 布尔原子操作
AtomicReference 对象引用原子操作
AtomicIntegerArray 整数数组原子操作
LongAdder 高并发累加,比 AtomicLong 性能更好

什么时候用:

  • 需要保证多线程安全地修改一个值时
  • 简单计数、状态标记等场景
  • 比 synchronized 性能更好
相关推荐
学到老活到老14 小时前
Spring 事务怎样生效?为什么加了 @Transactional 仍不回滚?
java·spring
学到老活到老14 小时前
Spring 怎样创建 Bean?@Autowired 在哪一步生效?
java·spring
用户1129361121914 小时前
我扫了项目里 739 个 Controller,发现最危险的越权漏洞不是没认证
java
小羊没烦恼!14 小时前
分布式事务 | 使用DTM 的Saga 模式
java·linux·运维·数据库·wpf
JPower_mr.g14 小时前
SmartCall v1.0.9 发布:智能体知识库上线,让 AI 客服先查资料再回答
java·ide·人工智能·macos·架构·开源·xcode
SL_staff15 小时前
破除执行黑箱:用目标地图、资源热力图与健康度看板构建可下钻的执行事实链
java·开源·全栈
骑着蜗牛撵大象32715 小时前
让 Codex 值夜班:把告警排查与巡检接成可回滚的自动化链路
android·java·运维·ai·自动化·codex·智能体
木头科技15 小时前
【AI 工程化第十八篇】Spring AI 语音 Agent 实战:实时转写、WebSocket、流式 TTS 与打断机制
java·人工智能·安全·spring·性能优化
cfm_291415 小时前
SpringPrototype作用域
java
大风起兮云飞扬丶15 小时前
Java——枚举
java·开发语言