Java动态线程数下可变长度整型数组的分区并行处理问题
问题诊断
你的代码存在两处核心错误:
- 任务提交逻辑错误:无论输入数组长度多少,都固定提交
threadCount个任务。当数组长度小于线程数时,会产生大量无意义的空任务,这就是你输出中出现大量线程启动日志却没有对应元素输出的原因。 - 分区计算逻辑错误:当前分区起止计算规则
i * threadCount~(i+1)*threadCount完全不符合分片逻辑,会引发两个问题:1)大数组场景下分片步长等于线程数,分片粒度不合理;2)分片结束位置大概率超过数组长度,存在ArrayIndexOutOfBoundsException风险。
解决方案
正确的分片逻辑需要同时适配数组长度小于/大于线程数的两种场景,你可以根据业务需求选择以下两种策略:
策略1:最大化并行,小数组每个元素单独分配任务
适合元素处理逻辑是计算密集型的场景,修正后代码如下:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) { int threadCount = Runtime.getRuntime().availableProcessors() * 2; // 限制线程数范围4~64 threadCount = Math.max(4, Math.min(64, threadCount)); ExecutorService executor = Executors.newFixedThreadPool(threadCount); final int[] inputArr = new int[]{1, 2, 4, 5}; int arrLength = inputArr.length; // 计算分片基础大小 int chunkSize = arrLength / threadCount; // 数组长度小于线程数时,每个分片1个元素 chunkSize = chunkSize == 0 ? 1 : chunkSize; // 计算实际需要提交的任务数 int taskCount = (int) Math.ceil((double) arrLength / chunkSize); for (int i = 0; i < taskCount; i++) { int start = i * chunkSize; int end = Math.min((i + 1) * chunkSize, arrLength); executor.submit(new Worker(inputArr, start, end)); } executor.shutdown(); try { executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } private static class Worker implements Runnable { private final int[] arr; private final int start; private final int end; public Worker(int[] arr, int startIndex, int endIndex) { this.arr = arr; this.start = startIndex; this.end = endIndex; } @Override public void run() { System.out.printf("Thread start: %d\n", Thread.currentThread().getId()); for (int i = this.start; i < this.end; i++) { System.out.println(arr[i]); } System.out.printf("Thread end: %d\n", Thread.currentThread().getId()); } } }
策略2:减少线程调度,小数组整个分配给单个任务
适合元素处理逻辑简单、小数组场景下减少线程切换开销,符合你给出的期望输出示例,只需要修改分片计算部分:
// 计算分片基础大小 int chunkSize = arrLength / threadCount; int taskCount; if (chunkSize == 0) { // 数组长度小于线程数时,只用1个任务处理全量数据 chunkSize = arrLength; taskCount = 1; } else { taskCount = (int) Math.ceil((double) arrLength / chunkSize); }
内容的提问来源于stack exchange,提问作者max42
相关产品推荐
相关产品推荐

