Java可变数量线程计算数组平均值结果异常问题排查
代码问题分析与修正
核心错误点
1. 累加变量类型错误导致精度丢失
parallelaverage方法中定义的int avg = 0;是整数类型,而Worker类的avg是double类型。当累加thread.avg时,浮点数会被强制转换为整数,小数部分直接被截断,这是结果偏差极大的主要原因。
2. Worker类的平均值计算逻辑冗余且易混淆
每个Worker在run方法中计算avg = (double)sum/a.length;,虽然数学上累加这些值等于总平均值,但这种做法提前引入了浮点运算,逻辑不够直观,还可能因后续修改引发错误。更合理的方式是让Worker保存自己负责区间的总和,最后由主线程统一计算总平均值。
3. 线程分割逻辑错误,线程数量不符合指定的p值
原代码通过for (int i = 0; i<a.length; i+=num)创建线程,当数组长度无法被p整除时,会创建超过p个线程。比如数组长度11、p=3时,num=3,循环会生成4个线程,既不符合“使用p个线程”的需求,还可能导致分割逻辑混乱。正确的分割应该是前p-1个线程处理num个元素,最后一个线程处理剩余的所有元素。
4. 异常处理过于简略
catch (Exception e){}直接忽略所有异常,出现线程中断等问题时无法排查错误,应该添加异常日志输出。
修正后的代码
Worker类(改为保存区间总和)
class Worker extends Thread { int[] a; int low; int upp; // 改为保存区间总和,避免提前浮点运算 long sum = 0; public Worker(int[] a, int low, int upp) { this.a = a; this.low = low; this.upp = upp; } public void run() { for (int i = low; i < upp; i++) { sum += a[i]; } } }
并行平均值计算方法
static double parallelaverage(int a[], int p) { double totalAvg = 0; int num = a.length / p; ArrayList<Worker> threads = new ArrayList<>(); // 创建前p-1个线程,每个处理num个元素 for (int i = 0; i < p - 1; i++) { Worker x = new Worker(a, i * num, (i + 1) * num); x.start(); threads.add(x); } // 最后一个线程处理剩余的所有元素 Worker lastWorker = new Worker(a, (p - 1) * num, a.length); lastWorker.start(); threads.add(lastWorker); // 等待所有线程完成 try { for (Worker thread : threads) { thread.join(); } } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } // 计算总和并求平均值 long totalSum = 0; for (Worker thread : threads) { totalSum += thread.sum; } totalAvg = (double) totalSum / a.length; return totalAvg; }
额外说明
- 使用
long类型保存区间总和,避免数组元素较多时int类型溢出。 - 明确控制线程数量为p个,完全符合需求。
- 主线程统一计算平均值,逻辑更清晰,精度更高。
内容的提问来源于stack exchange,提问作者sstows
相关产品推荐
相关产品推荐

