1)概念

Fork/Join 是JDK1.7加入的新的线程池实现,它体现的是一种分治思想,适用于能够进行任务拆分的cpu密集型运算。
任务拆分是指:将一个大任务拆分为算法上相同的小任务,直至不能拆分可以直接求解。跟递归相关的一些计算,如归并排序、斐波那契数列、都可以用分治思想进行求解。
Fork/Join在分治的基础上加入了多线程,可以把每个任务的分解和合并交给不同的线程来完成,进一步提升运算效率
简单讲,一个任务被分配给多个线程去执行。
Fork/Join默认会创建与cpu核心数大小相同的线程池,所以称之为密集型运算(cpu核心被完全利用)

2)使用

以计算数字累加和为例,阐述fork/join线程池工作原理:

  1. import java.util.concurrent.ForkJoinPool;
  2. import java.util.concurrent.RecursiveTask;
  3. import org.slf4j.*;
  4. public class TestForkJoin {
  5. public static void main(String[] args) {
  6. ForkJoinPool pool = new ForkJoinPool(4);
  7. System.out.println(pool.invoke(new MyTask(5)));
  8. }
  9. }
  10. class MyTask extends RecursiveTask<Integer>{
  11. public MyTask(int n) {
  12. this.n = n;
  13. }
  14. private int n;
  15. @Override
  16. protected Integer compute() {
  17. if (n==1){
  18. System.out.println(n);
  19. return n;
  20. }
  21. //任务拆分
  22. MyTask t1 = new MyTask(n-1);
  23. t1.fork();//提交给其它线程去完成t1任务
  24. //合并解雇
  25. int result = n+t1.join();
  26. return result;
  27. }
  28. }

如上例代码,ForkJoinPool线程池创建后,向其提交的任务类型不再是Runnable/Callable,而是需要自定义Task类继承RecursiveTask类或RecursiveAction类;

  • 继承RecursiveTask类,需要extends RecursiveTask,指定任务的返回类型;
  • 继承RecursiveAction类,表示任务无返回值;

本例中,compute方法为任务执行的代码,在任务中手动将任务再划分是fork/join线程池的思想。实现方法是fork()与join()方法。在任务代码中再创建一个子任务对象,调用该对象的fork方法再启动一个线程去执行此子任务,并通过该子任务对象的join方法返回结果。
image.png
从流程图可以看出,任务的多个线程之间还是串行执行,上层任务需要等待下层任务执行并返回结果;