Java线程共享变量问题:程序输出不符预期,求解决方案
解决线程竞态条件导致的输出异常问题
看起来你遇到了典型的线程竞态条件问题,这是多线程环境下共享资源未被正确同步时的常见bug。结合你的代码片段和输出表现,我来帮你分析和解决:
问题根源
从你的输出(重复输出1-6,最终只到1000而非预期的2000)来看,你的Race_Condition2线程类应该是多个线程共享了同一个计数器变量,并且对这个变量的读写操作没有任何同步保护。
举个实际场景:假设你的Race_Condition类里有一个普通计数器count,两个线程同时执行“读取计数器→输出→递增”的逻辑。由于count++不是原子操作(它拆分为读取、递增、写入三个独立步骤),很可能出现这种情况:线程A刚读取到count=6,还没来得及递增写入,线程B也读取到了count=6,最终两个线程都会输出6,然后各自把计数器改成7,就出现了重复输出的情况。同时因为没有同步控制,两个线程的操作互相干扰,最终计数器只递增到1000就停止了。
解决方案
你需要对共享资源的访问进行同步控制,确保同一时间只有一个线程能操作计数器。这里提供两种常见的可靠解决方法:
方法1:使用synchronized同步机制
修改你的Race_Condition类,把操作计数器的逻辑封装成同步方法,或者在操作代码块上加锁,保证同一时间只有一个线程能执行该逻辑:
// 共享计数器类 public class Race_Condition { private int count = 1; private final int MAX = 2000; // 同步方法,确保同一时间仅一个线程能执行 public synchronized void printNext() { if (count <= MAX) { System.out.print(count + " "); count++; } } // 供线程判断是否继续执行的同步方法(避免竞态) public synchronized boolean hasNext() { return count <= MAX; } } // 线程类:接收共享的计数器实例 public class Race_Condition2 extends Thread { private Race_Condition sharedCounter; public Race_Condition2(Race_Condition counter) { this.sharedCounter = counter; } @Override public void run() { while (sharedCounter.hasNext()) { sharedCounter.printNext(); } } } // 主类:创建一个共享计数器,传给两个线程 public class Race_ConditonTest { public static void main(String[] args) { Race_Condition counter = new Race_Condition(); Race_Condition2 R1 = new Race_Condition2(counter); Race_Condition2 R2 = new Race_Condition2(counter); R1.start(); R2.start(); } }
方法2:使用AtomicInteger原子类
Java的java.util.concurrent.atomic包提供了原子操作类,它们的核心操作是原子性的,不需要手动加锁,适合简单计数器场景:
import java.util.concurrent.atomic.AtomicInteger; // 共享计数器类 public class Race_Condition { private AtomicInteger count = new AtomicInteger(1); private final int MAX = 2000; public void printNext() { int current = count.getAndIncrement(); // 原子性的获取并递增 if (current <= MAX) { System.out.print(current + " "); } } public boolean hasNext() { return count.get() <= MAX; } }
这种方式底层通过CAS(比较并交换)机制实现原子操作,比手动加锁更简洁,性能也更优。
额外注意事项
- 确保线程共享同一个计数器实例:如果你的
Race_Condition2类里是每个线程自己new一个Race_Condition,那两个线程会各自输出1-1000,同样会出现重复输出且达不到2000的情况,所以一定要让所有线程使用同一个共享实例。 - 终止条件要同步:判断线程是否继续执行的逻辑也要保证线程安全,避免因为竞态条件导致线程提前退出或无限循环。
内容的提问来源于stack exchange,提问作者yoon
相关产品推荐
相关产品推荐

