java多线程进阶(八)Fork/Join任务拆分与合并
1、简单介绍
Fork和Join是任务的拆分与合并,因此它们并非单独的方法,而是要结合任务ForkJoinTask来使用。
ForkJoinTask有很多种实现,接下来简单的介绍几种
1.1、ForkJoinTask子类
RecursiveAction:不带返回值的任务
RecursiveATask:带返回值的任务
CountedCompleter:这是一个特殊的任务,fork让task异步执行,join让task同步执行,等待获取到返回值
1.2、重要方法
fork:创建一个异步执行的子任务
join:等待任务完成后返回结果
invoke:开始执行任务,并获得返回结果
1.3、WorkQueue工作队列
WorkQueue是内部的任务队列,是一个双端队列,后进先出,它属于每一个线程。
为了优化任务的执行效率,它采用了一种叫做工作窃取的算法,简单来说,就是当一个线程消耗光了它的任务之后,就会去其他的线程的队列头部来窃取一个任务来执行,由于是后进先出,所以不会对其他线程造成一个竞争影响。
1.4、ForkJoinPool线程池
ForkJoinTask有自己的线程池ForkJoinPool来进行线程服用,它有三个关键方法
invoke:提交任务并进行阻塞,直到任务完成返回合并结果
execute:异步执行任务,无返回值
submit:异步执行任务,返回task本身,可以通过task.get来获取结果
2、应用场景
public class Text { public static void main(String[] args) { ForkJoinPool pool = new ForkJoinPool(); ForkJoinTask<Integer> submit = pool.submit(new CountTask(1, 3)); try { Integer integer = submit.get(); System.out.println(integer); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } static class CountTask extends RecursiveTask<Integer> { private Integer start; private Integer end; public CountTask(Integer start, Integer end) { this.start = start; this.end = end; } @Override protected Integer compute() { System.out.println(start + "," + end); if (end - start > 20) { return createTask(); } else { int a = 0; for (int i = start; start <= end; i++) { a = a + i; } return a; } } private Integer createTask() { CountTask one = new CountTask(start, end / 2); one.fork(); CountTask two = new CountTask(end / 2, end); two.fork(); return one.join() + two.join(); } } }