Java中对Integer对象加synchronized锁未生效的原因是什么
问题错误原因
- 锁对象不是固定值:Java中
Integer是不可变类,代码中count += 1的操作本质是生成新的Integer实例赋值给count变量,等价于count = Integer.valueOf(count.intValue() + 1)。你将synchronized锁加在频繁变化的count对象上,会导致两个线程可能同时持有不同的锁对象进入临界区,自增操作的原子性无法得到保障,最终计数结果小于预期。 - Integer缓存特性加剧问题:Integer默认会缓存-128~127范围内的实例,当count数值还在该区间时,多个线程加锁的是同一个对象,此时不会出现并发问题;一旦count超过127,每次自增都会生成全新的Integer对象,锁直接失效,大量并发冲突会导致计数丢失。
修复方案
方案1:使用固定锁对象
声明一个不会发生变更的对象作为synchronized的锁,保证所有线程竞争的是同一把锁:
public class Test { // 改用基础类型int避免不必要的装箱拆箱 private static int count = 0; // 固定锁对象,final修饰保证不会被修改 private static final Object LOCK = new Object(); private static void add10K() { long idx = 0; while (idx++ < 1_0000_0000) { synchronized (LOCK){ count += 1; } } } public static long calc() { Thread th1 = new Thread(Test::add10K); Thread th2 = new Thread(Test::add10K); th1.start(); th2.start(); try { th1.join(); th2.join(); } catch (InterruptedException e) { e.printStackTrace(); } return count; } public static void main(String[] args) { System.out.println(calc()); } }
方案2:使用原子类优化性能
对于计数类场景,可以直接使用JUC包提供的原子类实现无锁原子操作,性能远高于手动加synchronized:
import java.util.concurrent.atomic.AtomicInteger; public class Test { // 原子整数类,自带原子操作能力 private static AtomicInteger count = new AtomicInteger(0); private static void add10K() { long idx = 0; while (idx++ < 1_0000_0000) { // 原子自增,无需手动加锁 count.incrementAndGet(); } } public static long calc() { Thread th1 = new Thread(Test::add10K); Thread th2 = new Thread(Test::add10K); th1.start(); th2.start(); try { th1.join(); th2.join(); } catch (InterruptedException e) { e.printStackTrace(); } return count.get(); } public static void main(String[] args) { System.out.println(calc()); } }
内容的提问来源于stack exchange,提问作者peter zhang
相关产品推荐
相关产品推荐

