java中用integer作synchronized锁对象常失效,根本原因是自增或重新赋值导致锁对象引用改变,且受integer缓存机制(-128~127)影响;应通过system.identityhashcode()验证锁对象一致性,并改用static final object等稳定锁对象。

Java中用Integer作synchronized锁对象,表面看加了锁,实际常失效——根本原因是锁对象在变,且受缓存机制干扰。排查这类问题,关键不是“找bug”,而是验证“锁是否真的锁住了同一个东西”。
看日志输出锁对象的唯一标识
在synchronized块前后,打印锁对象的System.identityHashCode()(不是hashCode(),后者可能被重写):
System.out.println("加锁前: " + System.identityHashCode(integer));synchronized(integer) { ... }System.out.println("加锁后: " + System.identityHashCode(integer));
如果同一轮循环里前后两个值不同,说明integer++已让引用指向新对象;如果多个线程打出的identityHashCode频繁变化或不一致,就证实锁对象不固定。
检查 Integer 的创建方式和取值范围
重点盯三类写法:
-
new Integer(100)→ 每次都是新对象,锁完全无效 -
Integer.valueOf(100)→ 在-128~127范围内复用缓存对象,看似“同一个”,但一旦发生++或重新赋值,立刻变成新对象 -
Integer i = 135;→ 等价于Integer.valueOf(135),超出缓存范围,每次都是新对象
只要锁对象是变量且参与自增、重新赋值等操作,就大概率出问题。
用字节码或调试器确认对象是否真的变了
反编译代码(javap -c YourClass),查看count++对应的实际指令:
- 必然包含
invokestatic java/lang/Integer.valueOf调用 - 接着是
putstatic把新对象写回字段
这说明:每次自增都生成新Integer实例,并更新引用。同步块锁的是旧引用,下一次进来时锁的已是另一个对象。
对比验证:换一个稳定锁对象再跑
把原代码中的synchronized(integer)临时替换成synchronized(lock),其中private static final Object lock = new Object();:
- 如果结果稳定为预期值(如1000),基本可断定原问题是锁对象不稳定
- 如果仍不正常,说明还有其他并发问题(如共享变量未用volatile修饰、非原子读写等)
这个对照实验成本低、结论直接,是快速定位的实用手段。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











