不能对包装类对象加锁,因其不可变且无法保护共享状态;应锁定可变的共享对象(如集合、业务类实例)或使用atomicinteger等并发工具。

Java 中包装类对象(如 Integer、String、Boolean 等)本身是不可变的,不能也不应该直接对它们加锁来实现线程安全——因为加锁目标必须是**可被多个线程共享且可能被修改的对象**,而包装类实例一旦创建就不能更改状态。
为什么不能对包装类对象加锁
包装类对象是 final 的、不可变的。例如:
-
Integer i = 100;创建的是一个只读对象,后续i = 200实际是新建了另一个对象并让引用指向它; - 多个线程即使持有同一个
Integer实例(比如常量池中的 -128~127 范围值),也无法通过它协调状态变更; - 对包装类对象
synchronized (i) { ... }虽语法合法,但毫无意义:锁住一个不变量无法保护任何共享状态,也不能阻止其他线程操作其他变量。
真正需要加锁的是共享的可变状态
线程安全的关键不在“锁什么类型”,而在“锁住谁”和“保护什么”。应锁定承载业务逻辑的**可变共享对象**,例如:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 自定义的共享容器(如
ArrayList、HashMap或自己写的计数器类); - 静态字段或实例字段所引用的集合、缓存、配置对象;
- 封装了状态和行为的业务对象(如订单管理器、连接池管理器)。
正确做法:用合适的锁保护共享数据结构
不要试图锁 Integer,而是锁住它所在的上下文:
- 若用
int count做计数器,应把count封装进一个类,并对该类实例加锁,或使用AtomicInteger; - 若用
Map<string integer></string>存共享计数,应锁整个 map 对象(或用ConcurrentHashMap); - 若调用
Collections.synchronizedMap(new HashMap()),锁的是内部的 mutex 对象,不是某个Integer值; - 若需复合操作(如“如果 key 不存在则 put 1”),必须显式同步整个 map 引用,而非 map 中的 value。
替代方案:优先使用无锁或专用并发工具
比起手动加锁,更推荐以下方式处理共享数值或简单状态:
-
AtomicInteger/AtomicLong:适用于计数、序列号等单变量原子更新; -
ConcurrentHashMap:替代HashMap + synchronized,支持高并发读写; -
CopyOnWriteArrayList:适合读多写少的监听器列表等场景; -
封装成线程安全容器类:如用
ReentrantLock包装PriorityQueue,锁的是队列实例本身,不是其中的Integer元素。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










