Java多线程随机数求和问题:5线程各生成1数但求和失效
问题分析与修复方案
咱们先来拆解下你的代码里导致求和失效的核心问题:
关键问题梳理
- 局部变量覆盖实例变量:你的
add方法里定义了参数int a,这会直接覆盖类中的实例变量a。同步块里执行的a += n其实是在修改这个局部变量,完全没触及用来累加的实例变量,等于做了无用功。 - 基本类型值传递陷阱:
main方法里的sum是基本类型int,传给summing构造函数时是复制了一份值,所以summing实例里的a和main的sum是完全独立的两个变量,就算实例里的累加逻辑正常,main里的sum也永远是0。 - 未等待线程执行完成:
main启动线程后直接结束,JVM可能在子线程还没完成计算时就退出了,你根本看不到最终的累加结果。
修复后的代码实现
方式一:手动同步保证线程安全
先修改summing类,把累加逻辑绑定到实例变量上,并提供结果获取方法:
import java.util.Random; public class Summing implements Runnable { // 用实例变量作为共享累加容器 private int total; public Summing() { this.total = 0; } @Override public void run() { generateAndAddRandomNumber(); } private void generateAndAddRandomNumber() { Random rand = new Random(); int n = rand.nextInt(10) + 1; System.out.println("Number generated: " + n); // 同步块锁定当前实例,保证累加操作原子性 synchronized (this) { total += n; } } // 线程安全的结果获取方法 public synchronized int getTotal() { return total; } }
再修改main方法,等待所有线程执行完成后再打印结果:
public class Main { public static void main(String[] args) throws InterruptedException { Summing sumCalculator = new Summing(); Thread t1 = new Thread(sumCalculator); Thread t2 = new Thread(sumCalculator); Thread t3 = new Thread(sumCalculator); Thread t4 = new Thread(sumCalculator); Thread t5 = new Thread(sumCalculator); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); // 等待所有子线程执行完毕 t1.join(); t2.join(); t3.join(); t4.join(); t5.join(); // 输出最终求和结果 System.out.println("Final sum: " + sumCalculator.getTotal()); } }
方式二:用AtomicInteger简化线程安全(推荐)
如果不想手动处理同步逻辑,可以用Java并发包提供的AtomicInteger,它本身就是线程安全的原子类,无需额外加锁:
import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; public class Summing implements Runnable { private AtomicInteger total = new AtomicInteger(0); @Override public void run() { Random rand = new Random(); int n = rand.nextInt(10) + 1; System.out.println("Number generated: " + n); // 原子性累加操作,自带线程安全 total.addAndGet(n); } public int getTotal() { return total.get(); } }
main方法和上面一致,通过join()等待所有线程完成后调用getTotal()即可。
修复逻辑说明
- 改用实例变量作为共享累加容器,让所有线程操作同一个变量,保证数据能正确累加。
- 用
join()让主线程等待子线程全部执行完毕,确保计算完成后再获取结果。 - 无论是手动同步还是
AtomicInteger,都避免了多线程下的竞态条件,保证累加操作的原子性。
内容的提问来源于stack exchange,提问作者Yoav Linder
相关产品推荐
相关产品推荐

