from: https://www.cnblogs.com/shipengzhi/articles/2067154.html
import java.util.concurrent.*; public class ConcurrentCalculator2 { //from: https://www.cnblogs.com/shipengzhi/articles/2067154.html private ExecutorService executorService; private CompletionService<Long> completionService; private int cpuCoreNumber; public ConcurrentCalculator2() { cpuCoreNumber = Runtime.getRuntime().availableProcessors(); executorService = Executors.newFixedThreadPool(cpuCoreNumber); completionService = new ExecutorCompletionService<Long>(executorService); } public Long sum(final int[] numbers) { for (int i = 0; i < cpuCoreNumber; i++) { //(页数)根据CPU核心个数拆分任务,创建FutureTask并提交到Executor int increment = numbers.length / cpuCoreNumber + 1; //(每页多少条) int start = increment * i; //首条数据-->当前页 的 int end = increment * i + increment; //首条数据-->(当前页+1)的 if (end > numbers.length) end = numbers.length; SumCalculator subCalc = new SumCalculator(numbers, start, end, (i+1)); if (!executorService.isShutdown()) { completionService.submit(subCalc); } } System.out.println("所有计算任务提交完毕, 主线程接着干其他事情!"); return getResult(); } public Long getResult() { //迭代每个只任务,获得部分和,相加返回 Long result = 0l; int index =0; System.out.println("-->2-"+ Thread.currentThread().getName()+"线程 List<Future<Long>>集合中的第一个元素开始遍历之前【就开始 全部执行掉MyCallable构造方法(不一定按集合内部顺序)!】"); for (int i = 0; i < cpuCoreNumber; i++) { try { index++; Long subSum = completionService.take().get(); System.out.println("-->4-"+Thread.currentThread().getName()+"线程 "+"-List<Future<Long>>集合遍历ing(一定按集合内部顺序)【有时候3和4会<成对>交叉执行】-- 打印第:"+index+"页累计的和:" + subSum); result += subSum; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } System.out.println("-->5-总结-->线程的实现方法总是先一步于List<Future<Long>>的遍历(线程的impl分页计算各页的总和,List<Future>负责把所有页的和累加!"); return result; } public void close() { executorService.shutdown(); } class SumCalculator implements Callable<Long> {//Runnable private int[] numbers; private int start; private int end; private int index; public SumCalculator(final int[] numbers, int start, int end, int index) { this.numbers = numbers; this.start = start; this.end = end; this.index = index; System.out.println("-->1-"+Thread.currentThread().getName() +"线程-生成子线程计算任务(调用构造函数)第 "+ index +"次"); } @Override public Long call() throws Exception { Long sum = 0l; for (int i = start; i < end; i++) { sum += numbers[i]; } //子线程-->休眠5秒钟,观察主线程行为,预期的结果是主线程会继续执行,到要取得FutureTask的结果是等待直至完成。 Thread.sleep(3000); System.out.println("-->3-" + Thread.currentThread().getName() + "线程执行计算任务 打印current数据:" +"startIndex:"+ start + ";endIndex:" + end+ ";sum:" + "=" + sum); return sum; } } public static void main(String[] args) { int[] numbers = new int[] { 0, 1, 2 }; ConcurrentCalculator2 calculator = new ConcurrentCalculator2(); Long sum = calculator.sum(numbers); System.out.println("-->10-res:"+sum); calculator.close(); } /** * Callable 和 Future接口 * Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。 * Callable和Runnable有几点不同: * (1)Callable规定的方法是call(),而Runnable规定的方法是run(). * (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 * (3)call()方法可抛出异常,而run()方法是不能抛出异常的。 * (4)运行Callable任务可拿到一个Future对象, * Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 * 通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。 */ }