应使用 AtomicInteger/AtomicLong 或 LongAdder 替代 Integer/Long 做限流计数器,避免自动装箱拆箱导致的线程不安全和 GC 开销;必要时用 Integer.valueOf() 复用缓存对象。

Java 中包装类在系统限流统计中处理计数器时,核心问题是避免 自动装箱/拆箱引发的线程安全问题和对象频繁创建开销。直接用 Integer、Long 等包装类型做共享计数器(如放在 ConcurrentHashMap<String, Integer> 中)会导致不可靠的递增行为,因为 i++ 操作不是原子的。
别用包装类直接做原子计数
以下写法是危险的:
map.putIfAbsent(key, 0); map.compute(key, (k, v) -> v + 1); // v 是 Integer,每次 new 新对象,且非原子
问题在于:v + 1 触发自动拆箱 → 计算 → 再装箱,中间可能被其他线程覆盖;同时每次生成新 Integer 实例,增加 GC 压力。
优先使用原子类替代包装类
对单个计数器,用 AtomicInteger 或 AtomicLong 替代 Integer/Long:
立即学习“Java免费学习笔记(深入)”;
-
ConcurrentHashMap<String, AtomicInteger>:每个 key 对应一个独立原子计数器 - 递增操作用
counter.incrementAndGet()或counter.addAndGet(1),线程安全且无装箱开销 - 初始化推荐用
map.computeIfAbsent(key, k -> new AtomicInteger(0)).incrementAndGet()
高并发场景考虑 LongAdder 提升性能
当计数器读多写少、且 QPS 极高(如每秒数万次更新)时,AtomicLong 的 CAS 竞争可能成为瓶颈:
- 改用
ConcurrentHashMap<String, LongAdder> -
LongAdder采用分段累加策略,写性能显著优于AtomicLong - 读取最终值用
longValue(),注意它不保证强一致性(适合限流这类容忍短暂滞后的场景)
必要时缓存常用包装类实例(仅限小整数)
如果业务逻辑确实需返回 Integer(如 HTTP 接口响应),可利用 Integer.valueOf(int) 的缓存机制减少对象创建:
-
Integer.valueOf(100)返回缓存对象(-128 ~ 127 范围内) - 避免
new Integer(100)或(Integer)100(后者等价于valueOf,安全) - 但不要依赖缓存做线程安全判断——缓存只优化内存,不解决竞态


















