java中包装类不可变且非线程安全,不能用于计数;atomicinteger基于cas实现无锁原子操作,是线程安全计数的正确选择,包装类仅可用于只读场景或与atomicinteger协同传递数据。

Java 中包装类(如 Integer、Long)本身是不可变的,不能直接用于线程安全的自增;真正实现无锁、线程安全计数的是 AtomicInteger 这类原子类——它底层基于 CAS(Compare-and-Swap)指令,不依赖 synchronized 锁,也不需要包装类参与运算逻辑。
为什么不用包装类做计数器
Integer 等包装类是 final 的,每次“++”都会创建新对象,例如:
Integer count = 0; count++; // 实际执行:count = Integer.valueOf(count.intValue() + 1);
这过程包含读取、加1、装箱、赋值四步,不是原子操作,在多线程下必然丢失更新。所以包装类只适合**只读场景或作为不可变数据载体**,不能承担计数职责。
AtomicInteger 才是无锁计数的正确选择
AtomicInteger 内部持有一个 volatile int value,所有自增方法(如 incrementAndGet())都通过 Unsafe 类调用 CPU 的 CAS 指令完成,保证单次读-改-写操作的原子性。
-
推荐用法:直接声明
AtomicInteger counter = new AtomicInteger(0); -
线程安全自增:调用
counter.incrementAndGet()或counter.getAndIncrement() -
避免误用包装类:不要写
Integer i = counter.get(); i++;—— 这又退化为非线程安全操作
包装类和 AtomicInteger 的合理配合方式
包装类可在以下场景与 AtomicInteger 协同,但**不参与计算过程**:
-
作为方法参数或返回值传递:比如日志打印、DTO 封装时,用
Integer.valueOf(counter.get())转为包装类(注意:这是只读转换,不影响原子性) -
与泛型集合/框架交互:某些老框架要求
List<integer></integer>,可临时用counter.get()构造元素,但计数逻辑仍由 AtomicInteger 独立维护 -
避免自动拆箱陷阱:不要对
AtomicInteger做类似(int) counter强转,它没有重载类型转换;必须显式调用.get()
常见误区提醒
-
别用 volatile Integer:仅用
volatile Integer count无法保证count++原子性,volatile 只保证可见性,不保证复合操作原子性 - 别混用 synchronized 和 AtomicInteger:二者目标一致(线程安全),混用不仅多余,还可能掩盖设计问题
-
注意初始值装箱开销:
new AtomicInteger(128)没问题,但若频繁构造大量 AtomicInteger 实例,注意对象分配压力——应尽量复用实例
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











