Fork/Join 框架

0 阅读2分钟

什么是Fork/Join框架

Fork/Join框架是Java 7 引入的一个用于并行计算的框架,它基于“分而治之”的思想,特别适合处理可以递归分解的任务。

其本质是将一个大任务拆分成多个小任务Fork),并行执行这些小任务,最后将各任务的结果合并Join)得到最终结果。

由于线程池的优化,提交的任务和线程数量并不是⼀对⼀的关系。在绝大多数情况下,⼀个物理线程实际上是需要处理多个逻辑任务的,每个线程必然需要拥有⼀个任务队列。在实际执⾏过程中,可能遇到这么⼀种情况:线程A已经把⾃⼰的任务都执⾏完了,⽽线程B还有⼀堆任务等着处理,此时,线程A就会“帮助”线程B,从线程B的任务队列中拿⼀个任务过来处理

这就通过工作窃取算法(Work-Stealing) 提高CPU利用率:每个工作线程维护一个双端队列,完成自己队列中的任务后,可以从其他线程队列的尾部“窃取”任务执行,减少线程空闲时间

使用示例

第一步:创建一个RecursiveTask的子类

该子类用于计算从startend的累加和。 如果startend的间隔小于THRESHOLD,则直接计算,如果大于THRESHOLD,则拆分任务。

class SumTask extends RecursiveTask<Long>{
        private final long start;
        private final long end;
        private static final long THRESHOLD=10_000;
        public SumTask(long start,long end){
            this.start=start;
            this.end=end;
        }
        @Override
        protected Long compute() {
            if(end-start<=this.THRESHOLD){
                long sum=0;
                for(long i=start;i<=end;i++){
                    sum+=i;
                }
                return sum;
            }else{
                long mid=(start+end)/2;
                SumTask leftTask=new SumTask(start,mid);
                SumTask rightTask=new SumTask(mid+1,end);
                leftTask.fork();
                rightTask.fork();
                long leftResult=leftTask.join();
                long rightResult=rightTask.join();
                return leftResult+rightResult;
            }
        }
    }

第二步:使用线程池执行任务

ForkJoinPool forkJoinPool=new ForkJoinPool();  
SumTask task=new SumTask(1,100_0000);  
Long result=forkJoinPool.invoke(task);  
System.out.println(result);

ForkJoinTask类

ForkJoinTaskJava并发编程中Fork/Join框架的核心抽象类,它代表了一个可以并行执行合并结果的任务。

它有两个子类:

  • RecursiveAction:用于没有返回值的任务(如并行排序、遍历)
  • RecursiveTask<V>:用于有返回值的任务(如并行求和、查找)

image.png