You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使多线程数组求和程序产生竞态条件(Race Condition)?

如何修改多线程求和程序以触发竞态条件?

你的代码之所以每次结果都正确,核心原因是每个线程都维护着独立的sum实例变量——每个线程只计算自己负责区间的和,最后再把这些完全隔离的结果相加。全程没有多个线程同时操作同一个共享变量,自然不会出现竞态条件。

要触发竞态条件,必须让多个线程同时操作同一个共享的累加变量。下面是两种简单的修改方案:

方案一:使用静态共享变量

把累加变量改成所有线程共享的静态变量,让所有线程直接修改它:

public class SyncDemo1 {
    // 所有线程共享的累加变量
    private static int totalSum = 0;

    public static void main(String[] args) {
        new SyncDemo1().startThread();
    }

    private void startThread() {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        
        // 所有线程操作同一个共享变量,区间划分保持不变
        MyThread thread1 = new MyThread(1, 200);
        MyThread thread2 = new MyThread(201, 400);
        MyThread thread3 = new MyThread(401, 600);
        MyThread thread4 = new MyThread(601, 800);
        MyThread thread5 = new MyThread(801, 1000);
        
        executor.execute(thread1);
        executor.execute(thread2);
        executor.execute(thread3);
        executor.execute(thread4);
        executor.execute(thread5);
        
        executor.shutdown();
        while (!executor.isTerminated()) {}
        
        System.out.println(totalSum);
    }

    private static void pause() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static class MyThread implements Runnable {
        private int from, to;

        public MyThread(int from, int to) {
            this.from = from;
            this.to = to;
        }

        public void run() {
            for (int i = from; i <= to; i++) {
                // 非原子操作:读->加->写,多线程下会互相覆盖
                totalSum += i;
                // 可选:加个微睡眠放大竞争概率
                // try { Thread.sleep(1); } catch (Exception e) {}
            }
            pause();
        }
    }
}

方案二:用共享对象封装变量

把共享变量封装到一个对象里,让所有线程操作同一个对象的属性:

public class SyncDemo1 {
    public static void main(String[] args) {
        new SyncDemo1().startThread();
    }

    private void startThread() {
        // 共享的累加器对象,所有线程共用
        SumHolder sumHolder = new SumHolder();
        ExecutorService executor = Executors.newFixedThreadPool(5);
        
        MyThread thread1 = new MyThread(sumHolder, 1, 200);
        MyThread thread2 = new MyThread(sumHolder, 201, 400);
        MyThread thread3 = new MyThread(sumHolder, 401, 600);
        MyThread thread4 = new MyThread(sumHolder, 601, 800);
        MyThread thread5 = new MyThread(sumHolder, 801, 1000);
        
        executor.execute(thread1);
        executor.execute(thread2);
        executor.execute(thread3);
        executor.execute(thread4);
        executor.execute(thread5);
        
        executor.shutdown();
        while (!executor.isTerminated()) {}
        
        System.out.println(sumHolder.getSum());
    }

    private static void pause() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    // 封装共享累加变量的类
    private static class SumHolder {
        private int sum = 0;
        
        public void add(int value) {
            // 同样是非原子操作,会引发竞态条件
            sum += value;
        }
        
        public int getSum() {
            return sum;
        }
    }

    private static class MyThread implements Runnable {
        private SumHolder sumHolder;
        private int from, to;

        public MyThread(SumHolder sumHolder, int from, int to) {
            this.sumHolder = sumHolder;
            this.from = from;
            this.to = to;
        }

        public void run() {
            for (int i = from; i <= to; i++) {
                sumHolder.add(i);
            }
            pause();
        }
    }
}

为什么会出现数据不一致?

sum += i这类操作本质上是三个独立的步骤:

  1. 从主内存读取当前sum的值到线程的工作内存
  2. 在工作内存中把读取的值和i相加
  3. 把计算结果写回主内存的sum变量

当多个线程同时执行这三个步骤时,就会出现"覆盖"问题:比如线程A和线程B同时读取到sum=100,线程A计算后写回101,线程B计算后写回102,最终sum的值是102,而正确结果应该是103——这就丢失了一次累加操作,导致最终结果小于预期的500500,且每次运行结果都会不同。

内容的提问来源于stack exchange,提问作者Rex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:45:17