Integer的i++操作涉及1次自动拆箱(intValue)和1次自动装箱(valueOf),非原子,存在线程安全问题及NPE风险;应改用AtomicInteger或synchronized等线程安全方案。

在多线程环境下对 Integer 执行 i++ 操作,**总共涉及 2 次自动拆箱 + 1 次自动装箱**,且整个过程不是原子操作,存在严重线程安全问题。
拆箱:取值阶段(2 次)
Java 中的 i++ 是复合操作,等价于 i = i + 1。而 i + 1 是数值运算,要求操作数必须是基本类型,因此编译器需先将 i(Integer)拆箱:
- 第一次拆箱:计算
i + 1时,i被调用intValue()→ 得到int值 - 注意:虽然只写了一次
i,但语义上它既参与加法(作为左操作数),又作为赋值目标;不过 JVM 字节码层面,i++对应的是getfield+iconst_1+iadd+putfield,其中getfield读取对象字段后,紧接着就是intValue()调用 —— 这是唯一一次显式拆箱。但关键在于:这个“取值”动作本身不包含第二次拆箱。
更准确地说:仅 1 次拆箱用于获取当前值参与运算。所谓“2 次”常见误解源于混淆了表达式结构,实际字节码验证显示:对 Integer 变量执行 i++,编译后只插入一次 intValue() 调用(用于加载值),然后做整数加法,最后装箱赋值。
装箱:赋值阶段(1 次)
加法结果是 int 类型,而左侧变量 i 是 Integer 类型,所以必须将结果重新包装为对象:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 调用
Integer.valueOf(int)完成自动装箱 - 该方法会检查值是否在 [-128, 127] 缓存范围内,决定复用缓存对象还是新建实例
为什么不能在多线程中直接用 Integer++
因为 i++ 不是原子操作,完整流程为:
- 线程 A 读取 i(拆箱)→ 得到 100
- 线程 B 同时读取 i(拆箱)→ 也得到 100
- A 计算 100+1=101,装箱后写回 i
- B 计算 100+1=101,装箱后写回 i(覆盖 A 的结果)
- 最终 i = 101,而非预期的 102
此外,若 i 为 null,拆箱瞬间抛出 NullPointerException。
替代方案(线程安全)
避免使用 Integer 做并发自增:
- 用
AtomicInteger:支持incrementAndGet()等原子操作,底层基于 CAS - 用
int配合synchronized或ReentrantLock - Redis 场景下,优先用服务端原子指令(如
INCR),而非取回再自增

















