多线程工具ForkJoinPool

package com.wangbiao.consumer.consumercontroller;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * ForkJoinPool
 *
 * ForkJoinPool : 专门用来运行 ForkJoinTask 的线程池,(在实际使用中,也可以接收Runnable/Callable 任务,但在真正运行时,
 * 也会把这些任务封装成 ForkJoinTask 类型的任务)。
 *
 *
 * 他是 fork/join 框架的核心,是 ExecutorService 的一个实现,用于管理工作线程,并提供了一些工具来帮助获取有关线程池状态和性能的信息。
 *
 * 工作线程一次只能执行一个任务。
 *
 * ForkJoinPool 线程池并不会为每个子任务创建一个单独的线程,相反,池中的每个线程都有自己的双端队列用于存储任务 ( double-ended queue )。
 *
 * 这种架构使用了一种名为工作窃取( work-stealing )算法来平衡线程的工作负载。
 * 工作窃取( work-stealing )算法
 *
 * 要怎么解释 「 工作窃取算法 」 呢 ?
 *
 * 简单来说,就是空闲的线程试图从繁忙线程的 deques 中 窃取工作。
 *
 * 默认情况下,每个工作线程从其自己的双端队列中获取任务。但如果自己的双端队列中的任务已经执行完毕,
 * 双端队列为空时,工作线程就会从另一个忙线程的双端队列尾部或全局入口队列中获取任务,因为这是最大概率可能找到工作的地方。
 *
 * 这种方法最大限度地减少了线程竞争任务的可能性。它还减少了工作线程寻找任务的次数,因为它首先在最大可用的工作块上工作。
 */
//有结果返回的任务
public class MyRecursiveTask extends RecursiveTask<Integer> {
    private Integer startValue; //子任务的开始计算的值
    private Integer endValue; //子任务结束计算的值

    public MyRecursiveTask(Integer startValue, Integer endValue) {
        this.startValue = startValue;
        this.endValue = endValue;
    }

    /**
     *  对于fork/join来说,在使用时还是存在下面的一些问题的:
     *
     *     在使用JVM的时候我们要考虑OOM的问题,如果我们的任务处理时间非常耗时,并且处理的数据非常大的时候,会造成OOM;
     *     ForkJoin是通过多线程的方式进行处理任务,那么我们不得不考虑是否应该使用ForkJoin。因为当数据量不是特别大的时候,
     *     我们没有必要使用ForkJoin。因为多线程会涉及到上下文的切换,所以数据量不大的时候使用串行比使用多线程快;
     *所以这里设计了个500,500以下不适用ForkJoin
     */
    private static final Integer MAX = 500;

    @Override
    protected Integer compute() {
        //小于200不用做任务拆分
        if (startValue - endValue < MAX) {
            System.out.println("开始计算:startValue:" + startValue + " ; endValue:" + endValue);

            Integer totalValue = 0;
            for (int i = this.startValue; i <= this.endValue; i++) {
                totalValue += i;
            }
            return totalValue;
        }
        MyRecursiveTask myRecursiveTask0 = new MyRecursiveTask(startValue, (startValue + endValue) / 2);
        myRecursiveTask0.fork();//让task异步执行
        MyRecursiveTask calcForJoinTask1 = new MyRecursiveTask((startValue + endValue) / 2 + 1, endValue);
        calcForJoinTask1.fork();//让task异步执行

        return myRecursiveTask0.join()+calcForJoinTask1.join();//让task同步执行,可以获取返回值
    }

    public static void main(String[] args) {
        MyRecursiveTask calcForJoinTask = new MyRecursiveTask(1, 1000);

        // 这是Fork/Join框架的线程池
        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Integer> taskFuture = pool.submit(calcForJoinTask);
        try {
            Integer result = taskFuture.get();
            System.out.println("result:" + result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }


}

 

CountedCompleter:无返回值任务,完成任务后可以触发回调
RecursiveAction:无结果返回的任务

 

posted @ 2022-06-26 15:47  余生请多指教ANT  阅读(16)  评论(0编辑  收藏  举报