jdk1.5前用
jdk1.5出现了
从接口的使用便利程度上远胜Thread,更不用说在java.util.concurrent包中的各种线程池,Future类和Lock等便利工具,由于ExecuteService是接口,面向接口编程的实现只需要实现该接口即可。
{ private ExecuteService executeService; private int parallism; // 构造函数 public xxxx(){ parallism = Runtime.getRuntime().avaliableProcessors();// 线程池个数,默认cpu的核心数 executeService = Executors.newFixedPoolThread(parallism); } //处理计算任务的线程 private static class SumTask implements Callable<Long> { private long[] numbers; private int from; private int to; public SumTask(long[] numbers, int from, int to) { this.numbers = numbers; this.from = from; this.to = to; } @Override public Long call() { long total = 0; for (int i = from; i <= to; i++) { total += numbers[i]; } return total; } } @Override public long sumUp(long[] numbers) { List<Future<Long>> results = new ArrayList<>(); // 把任务分解为 n 份,交给 n 个线程处理 4核心 就等分成4份呗 // 然后把每一份都扔个一个SumTask线程 进行处理 int part = numbers.length / parallism; for (int i = 0; i < parallism; i++) { int from = i * part; //开始位置 int to = (i == parallism - 1) ? numbers.length - 1 : (i + 1) * part - 1; //结束位置 //扔给线程池计算 results.add(pool.submit(new SumTask(numbers, from, to))); } // 把每个线程的结果相加,得到最终结果 get()方法 是阻塞的 // 优化方案:可以采用CompletableFuture来优化 JDK1.8的新特性 long total = 0L; for (Future<Long> f : results) { try { total += f.get(); } catch (Exception ignore) { } } return total; } }是ExecuteService的补充,不是替代。
ExecuteSerivice是所有核心线程共享一个队列,当一个任务执行完成就会自动从队列中取出任务执行,而ForkJoinPool强调的是工作窃取算法。就是线程任务执行完成后会寻找未被执行的任务并且执行任务。
区别在于ForkJoinPool的分而治之的方法。ForkJoinPool会把任务递归细分成许多更小的任务,并且把任务的结果返回执行。而ExecuteService也可以实现这个方法,只是写的代码更麻烦一些。而ForkJoinPool的fork()方法为执行线程,join()为返回的结果。
{ private ForkJoinPool pool ; //执行任务RecursiveTask:有返回值 RecursiveAction:无返回值 private static class SumTask extends RecursiveTask<Long> { private long[] numbers; private int from; private int to; public SumTask(long[] numbers, int from, int to) { this.numbers = numbers; this.from = from; this.to = to; } //此方法为ForkJoin的核心方法:对任务进行拆分 拆分的好坏决定了效率的高低 @Override protected Long compute() { // 当需要计算的数字个数小于6时,直接采用for loop方式计算结果 if (to - from < 6) { long total = 0; for (int i = from; i <= to; i++) { total += numbers[i]; } return total; } else { // 否则,把任务一分为二,递归拆分(注意此处有递归)到底拆分成多少分 需要根据具体情况而定 int middle = (from + to) / 2; SumTask taskLeft = new SumTask(numbers, from, middle); SumTask taskRight = new SumTask(numbers, middle + 1, to); taskLeft.fork(); taskRight.fork(); return taskLeft.join() + taskRight.join(); } } } // 构造函数 public xxxx(){ pool = new ForkJoinPool(); } public long sumUp(long[] numbers) { Long result = pool.invoke(new SumTask(numbers, 0, numbers.length - 1)); pool.shutdown(); return result; } }用ForkJoinPool的场景是 :计算数量密集型的任务。
java自学网站
ForkJoinPool参考博客网址
