Java 原子类怎么用
在日常写代码时,你是不是遇到过这种情况:多个同事同时改同一个Excel表格的单元格,最后统计的总数不对?这就是“多线程抢资源”的问题,放到程序里也是一样——如果多个线程同时改一个共享变量,很容易算出错的结果。Java原子类就是解决这个问题的“Excel锁定工具”,专门帮你在多线程场景下安全改变量。
先搞懂:为什么普通变量会出问题?
举个生活化的例子:你和朋友同时在ATM机上查余额,都是1000元,然后各自取500元。你先取,把余额改成500元;这时候朋友的屏幕还是1000元,他也改成500元。最后ATM里少了1000元,只剩500元,这就是多线程并发的“超卖/超取”问题。

普通变量(比如int类型)的自增操作,其实是“读-改-写”三步:先拿旧值,加1,再写回去。如果两个线程同时读旧值,就会出现上面的错误。Java原子类的核心,就是把这三步变成“原子操作”——要么一次性成功,要么全失败,不会被其他线程打断。
原子类怎么用?从“计数器”例子入门
原子类用起来特别简单,不用复杂的锁,直接创建对象调用方法就行。最常用的是AtomicInteger(对应int类型的原子类),我们用它做一个多线程计数器:
`java
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicDemo {
// 原子计数器,初始值0
private static final AtomicInteger COUNT = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
// 10个线程同时给计数器加1,各加1000次
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
// 核心方法:原子性加1,返回更新后的值
COUNT.incrementAndGet();
}
}).start();
}
// 等所有线程跑完,打印结果
Thread.sleep(1000);
System.out.println("最终计数器值:" + COUNT.get());
}
}
`
如果把AtomicInteger换成普通int,大概率会出现“9999”“10001”这种错值,用原子类的话,结果肯定是10000,完美解决并发问题。
常用原子类对应不同场景
不用记太多,常用的原子类就4种,对应不同的变量类型:
- AtomicInteger:对应普通int,适合计数器、编号生成这类整数场景;
- AtomicLong:对应long类型,比如统计系统总请求数,避免int不够用;
- AtomicBoolean:对应boolean,比如做“一次性任务标记”——标记任务是否执行过,保证只有一个线程能设为true;
- AtomicReference:对应自定义对象,比如要线程安全地更新用户信息,用它比自己写锁省心。
用原子类的注意事项
原子类虽然好用,但不能随便用,记住两个关键点:
第一,它只能保证单个操作的原子性,如果是多个操作组合,还是会出问题。比如你要“先判断当前值是10,再改成20”,不能直接用AtomicInteger的普通方法,得用compareAndSet(CAS方法):
`java
// 只有当前值是10时,才改成20,成功返回true,失败返回false
boolean success = COUNT.compareAndSet(10, 20);
`
这个方法就像你去买奶茶,必须是你点的那杯(当前值)才会给你,不是的话就重新排队,不会搞错。
第二,它适合“轻量并发”,如果是几十上百个线程抢同一个变量,原子类的效率会下降,这时候改用锁更合适,不用所有场景都硬套原子类。
简单来说,Java原子类就是多线程场景下的“安全操作小工具”,不用写复杂锁,用对方法就能解决大部分并发变量的问题,是写高并发Java代码的基础小技巧。