synchronized块锁失效原因:多线程自增结果不符预期
为什么synchronized块用Integer做锁无法保证线程安全?
你的代码中两个线程各自对cnt执行10万次自增操作,预期结果应为200000,但实际输出偏小,核心问题出在锁对象本身被动态改变,导致同步机制失效:
问题根源
Integer是不可变类,cnt++并非直接修改原对象的值,而是执行了cnt = Integer.valueOf(cnt.intValue() + 1)——每次自增都会创建一个新的Integer对象,并让cnt指向这个新对象。- synchronized块锁的是当前
cnt指向的对象实例,每次自增后cnt指向的对象发生变化,两个线程可能各自持有不同对象的锁,完全起不到互斥作用,最终出现多个线程同时修改值的线程安全问题,导致计数丢失。
解决方案
针对这个问题,有几种可靠的修复方式:
1. 使用固定不变的锁对象
在SharedObject类中定义一个固定的锁对象,确保所有线程都锁定同一个实例:
public class Main { public static void main(String[] args) throws InterruptedException { SharedObject sharedObject = new SharedObject(); Thread producer = new Thread(sharedObject::produce); Thread consumer = new Thread(sharedObject::consume); producer.start(); consumer.start(); producer.join(); consumer.join(); System.out.println(sharedObject.cnt); } static class SharedObject { int cnt = 0; // 固定锁对象,始终指向同一个实例 private final Object lock = new Object(); void produce() { for(int i=0; i<100000; i++) { synchronized (lock) { cnt++; } } } void consume() { for(int i=0; i<100000; i++) { synchronized (lock) { cnt++; } } } } }
2. 使用AtomicInteger原子类
利用Java并发包提供的原子类,无需手动加锁即可实现线程安全的自增操作:
import java.util.concurrent.atomic.AtomicInteger; public class Main { public static void main(String[] args) throws InterruptedException { SharedObject sharedObject = new SharedObject(); Thread producer = new Thread(sharedObject::produce); Thread consumer = new Thread(sharedObject::consume); producer.start(); consumer.start(); producer.join(); consumer.join(); System.out.println(sharedObject.cnt.get()); } static class SharedObject { AtomicInteger cnt = new AtomicInteger(0); void produce() { for(int i=0; i<100000; i++) { cnt.incrementAndGet(); } } void consume() { for(int i=0; i<100000; i++) { cnt.incrementAndGet(); } } } }
3. 锁定当前对象或使用synchronized方法
如果不需要单独的锁对象,也可以直接锁定this(当前SharedObject实例),或者把方法声明为synchronized:
public class Main { public static void main(String[] args) throws InterruptedException { SharedObject sharedObject = new SharedObject(); Thread producer = new Thread(sharedObject::produce); Thread consumer = new Thread(sharedObject::consume); producer.start(); consumer.start(); producer.join(); consumer.join(); System.out.println(sharedObject.cnt); } static class SharedObject { int cnt = 0; // 使用synchronized方法,锁对象为当前实例this synchronized void produce() { for(int i=0; i<100000; i++) { cnt++; } } synchronized void consume() { for(int i=0; i<100000; i++) { cnt++; } } } }
内容的提问来源于stack exchange,提问作者madina11906036
相关产品推荐
相关产品推荐

