Thread类无法更新调用类的共享数组问题求助
多线程实现productExceptSelf结果全为0的问题排查与修复
核心问题分析
静态nums变量未赋值
Solution类中定义了静态nums数组,但在productExceptSelf方法里,仅接收了方法参数nums,并未将其赋值给静态变量。Threaded类的run方法调用getProduct(nums, i)时,此处的nums是未初始化的静态变量(值为null),导致getProduct方法中访问nums.length抛出NullPointerException,线程异常终止,无法修改answer数组,最终answer保持初始的全0状态。线程等待逻辑不可靠
使用while(threadgrp.activeCount() > 0)的忙等方式存在缺陷:activeCount()返回的是线程组活跃线程的估计值,无法保证准确性,可能导致主线程提前退出,子线程尚未完成计算。冗余参数与变量作用域问题
Threaded类的getProduct方法接收了nums参数,但实际调用时传入的是未初始化的静态nums,参数本身冗余且容易引发混淆。
修复方案
方案1:移除静态变量,改用内部类捕获外部变量(推荐)
避免静态变量带来的线程安全和作用域问题,直接在子线程中使用方法参数nums,同时用join()等待所有线程完成:
class Solution { public int[] productExceptSelf(int[] nums) { int n = nums.length; int[] answer = new int[n]; Thread[] threads = new Thread[n]; for (int i = 0; i < n; i++) { final int idx = i; // 保证lambda中变量有效final threads[i] = new Thread(() -> { int product = 1; for (int j = 0; j < n; j++) { if (j != idx) { product *= nums[j]; } } answer[idx] = product; }); threads[i].start(); } // 等待所有子线程执行完成 for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("线程被中断", e); } } return answer; } }
方案2:修正静态变量赋值与线程等待逻辑
如果坚持使用独立的Threaded类,需确保静态变量正确赋值,并改用可靠的线程等待方式:
class Solution { public static int[] nums; public static int[] answer; public int[] productExceptSelf(int[] inputNums) { nums = inputNums; // 给静态nums赋值 int n = nums.length; answer = new int[n]; Thread[] threads = new Thread[n]; for (int i = 0; i < n; i++) { threads[i] = new Threaded(i); threads[i].start(); } // 等待所有线程完成 for (Thread t : threads) { try { t.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } } return answer; } } class Threaded extends Thread { int i; Threaded(int i) { this.i = i; } @Override public void run() { answer[i] = getProduct(); } private int getProduct() { int x = 1; for (int j = 0; j < Solution.nums.length; j++) { if (i != j) { x *= Solution.nums[j]; } } return x; } }
额外建议:多线程并非最优解
你最初用多线程是为了解决单线程超时问题,但实际上productExceptSelf存在时间复杂度O(n)、空间复杂度O(1)(除输出数组)的最优解法,比多线程更高效,完全不会超时:
class Solution { public int[] productExceptSelf(int[] nums) { int n = nums.length; int[] answer = new int[n]; // 计算前缀乘积:answer[i]是nums[0..i-1]的乘积 answer[0] = 1; for (int i = 1; i < n; i++) { answer[i] = answer[i-1] * nums[i-1]; } // 计算后缀乘积并合并:suffix是nums[i+1..n-1]的乘积 int suffix = 1; for (int i = n-1; i >= 0; i--) { answer[i] *= suffix; suffix *= nums[i]; } return answer; } }
内容的提问来源于stack exchange,提问作者Ashish Vashisht
相关产品推荐
相关产品推荐

