多线程计数器同步问题求助:AtomicInteger与普通变量同步异常
问题分析与解决
问题原因
你遇到的核心问题是线程执行时机的不确定性:
- t1、t2、t3三个线程同时启动,t3的打印操作可能在t1、t2还没完成所有500次递增时就执行,所以每次打印的都是计数器的中间值,而非最终的1000。
- 你提到注释掉
atomicIntegers.increment()后a能得到正确1000,这只是偶然现象——某次运行中t1、t2刚好在t3开始打印前完成了所有递增,并非注释increment()本身解决了问题。线程调度不可控,这种偶然结果不具备通用性。
另外,你的AtomicIntegers类继承Thread属于冗余设计,它只是一个计数器工具类,完全不需要继承线程类。
解决方案
1. 确保t3在t1、t2执行完成后再打印
在启动t3前,调用t1和t2的join()方法,让主线程等待t1、t2执行完毕后再启动t3:
public static void main(String args[]) throws InterruptedException { AtomicIntegers atomicIntegers = new AtomicIntegers(); Thread t1= new Thread() { @Override public void run() { for(int i =0; i<500; i++) { atomicIntegers.incrementBoth(); } } }; Thread t2= new Thread() { @Override public void run() { for(int i =0; i<500; i++) { atomicIntegers.incrementBoth(); } } }; Thread t3= new Thread() { @Override public void run() { System.out.println("atomicInteger最终值: " + atomicIntegers.getAtomicInteger()); System.out.println("a最终值: " + atomicIntegers.getA()); } }; t1.start(); t2.start(); // 等待t1、t2执行完毕 t1.join(); t2.join(); // 再启动t3打印最终结果 t3.start(); }
2. 实现两个计数器的同步递增
要保证atomicInteger和a每次都同步递增(即单次操作同时更新两个值),需要把两个递增逻辑放在同一个同步上下文里,避免出现一个更新、另一个未更新的不一致情况:
// 重构工具类,去掉不必要的Thread继承 class AtomicIntegers { private AtomicInteger atomicInteger = new AtomicInteger(0); private int a = 0; private final ReentrantLock lock = new ReentrantLock(); // 同步递增两个计数器 public void incrementBoth() { lock.lock(); try { atomicInteger.incrementAndGet(); a++; } finally { lock.unlock(); } // 也可以用synchronized块替代锁,效果一致 // synchronized (this) { // atomicInteger.incrementAndGet(); // a++; // } } public int getAtomicInteger() { return atomicInteger.get(); } public int getA() { lock.lock(); try { return a; } finally { lock.unlock(); } } }
修改后,t1、t2每次调用incrementBoth()都会同步更新两个计数器,t3则会在t1、t2完成所有操作后打印最终值,两个计数器的结果都会稳定为1000。
内容的提问来源于stack exchange,提问作者Nitin Gangwar
相关产品推荐
相关产品推荐

