简述
场景
合并运算的场景,例如批量数据组合运算。
例如在合并两个来源的数据时,我们往往需要通过两个方法来分别获取数据。当数据量或等待时间过长时,我们可以将这两个方法并行执行来缩短执行时间。
通常使用
- 通过
fork()
方法将任务交给任务池异步执行
- 使用
join()
方法阻塞式获取执行结果
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static void main(String[] args) throws Exception { ForkJoinTask<Integer> task = new RecursiveTask<Integer>() { @Override protected Integer compute() { try { Thread.sleep(1200); } catch (InterruptedException ignored) { } System.out.println("计算完成"); return 123; } }; task.fork(); Thread.sleep(1000); System.out.println("主线程完成"); Integer result = task.join(); System.out.println("计算结果:" + result); }
|
方法简述
fork
将任务推送到任务队列中异步执行。
由于ForkJoinTask
的状态机制,导致了在任务执行途中(isDone()
方法返回false时)再次调用fork
时,会再次推送任务并异步执行。
但由于fork
的返回值是自身,因此在fork
后的join
中,只会返回最近的一次缓存结果。
join
等待进行中的任务并返回运算结果。
当任务被多次执行时,则会等待最后一次任务的执行返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public static void main(String[] args) throws Exception { ForkJoinTask<Integer> task = new RecursiveTask<Integer>() { @Override protected Integer compute() { try { Thread.sleep(1200); } catch (InterruptedException ignored) { } int i = new Random().nextInt(100); System.out.println("计算完成 - " + i); return i; } }; task.fork(); Thread.sleep(200); task.fork(); Thread.sleep(200); task.fork(); Integer join = task.join(); System.out.println(join); }
|
这里的返回结果就是最后一次fork
中计算的结果。
invoke
invoke方法实质上是让任务尝试执行,阻塞并返回结果。
有一点值得注意,在调用invoke方法时,若任务处于运行中时,则任务会被再次执行。若任务已经结束,则直接返回结果。
示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public static void main(String[] args) throws Exception { ForkJoinTask<Integer> task = new RecursiveTask<Integer>() { @Override protected Integer compute() { try { Thread.sleep(1200); } catch (InterruptedException ignored) { } int i = new Random().nextInt(100); System.out.println("计算完成 - " + i); return i; } }; task.fork(); Thread.sleep(1000); System.out.println("主线程完成"); task.invoke(); System.out.println("计算结果:" + task.getRawResult()); task.invoke(); System.out.println("计算结果:" + task.getRawResult()); }
|
此时的结果输出如下:
1 2 3 4 5
| 主线程完成 计算完成 - 92 计算完成 - 21 计算结果:21 计算结果:21
|
getRawResult
直接返回任务的缓存结果。若无结果则返回null
。