两线程共享对象变量递增未达预期值的原因咨询
多线程递增共享变量结果不符合预期的根源解析
你的两种猜测本质上是同一问题的不同表现,核心原因是递增操作不是原子性的,且没有同步机制保障线程间的内存可见性。
具体执行过程拆解
myObject.setX(myObject.getX() + 1) 这个逻辑会被拆分为三个独立的非原子步骤:
- 从主内存读取
myObject.x的值到当前线程的本地内存 - 在本地内存中对读取到的值执行
+1运算 - 将计算后的结果写回主内存的
myObject.x
问题场景示例
假设初始时x=100,两个线程的执行时序可能如下:
- 线程A读取
x的值为100 - 线程调度器切换到线程B,线程B也读取
x的值为100 - 线程B完成
+1运算,得到101,写回主内存,此时x=101 - 调度器切回线程A,线程A继续执行
+1运算得到101,再写回主内存,最终x还是101
这就导致两次递增操作只产生了一次的效果,相当于其中一次递增的结果被覆盖了。
你提到的两种情况其实是这个过程的不同阶段:
- 第一种描述的是线程在执行中间步骤时被切换,写回动作滞后;
- 第二种描述的是两个线程同时读取了旧值,最终互相覆盖结果;
两者都是原子性缺失带来的必然问题。
代码额外问题
如果你的MyObject类中getX()和setX()是普通的读写方法(未加锁、未用volatile修饰变量),还会存在可见性问题:线程对x的修改可能不会立即同步到主内存,其他线程读取到的可能是过期的旧值,进一步导致结果偏差。
解决思路
- 给
getX()和setX()方法加上synchronized修饰,或者在递增逻辑的代码块上加锁,保证同一时间只有一个线程执行完整的递增操作; - 使用
java.util.concurrent.atomic.AtomicInteger替代普通int,它的incrementAndGet()方法是原子性的,能直接保证递增操作的线程安全; - 注意:
volatile关键字只能保证变量的可见性,无法保证递增操作的原子性,所以单独使用volatile解决不了这个问题,需要配合锁或原子类。
内容的提问来源于stack exchange,提问作者Marwane
相关产品推荐
相关产品推荐

