• ForkAndJoin框架概念


         ForkJoinPool是ExecutorService接口的实现,它专为可以递归分解成小块的工作而设计。

    fork/join框架将任务分配给线程池中的工作线程,充分利用多处理器的优势。

         使用fork/join框架的第一步是编写一部分工作的代码。类似的伪代码如下:

    如果(当前工作部分足够小)
        直接做这项工作
    其他
       把当前工作分成两部分
       调用这两个部分并等待结果

         将此代码包装在ForkJoinTask子类中,通常是RecursiveTask(可以返回执行结果)或者RecursiveAction。

          假如有一个从1累加到100的需求,使用forkAndJoin框架可以如下实现:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ForkJoinPool;
    import java.util.concurrent.RecursiveTask;
    
    public class ForkAndJoin {
    
        //获得执行ForkAndJoin任务的线程池
        private static final ForkJoinPool forkJoinPool = (ForkJoinPool) Executors.newWorkStealingPool();
    
    
        public static void main(String args[]) throws ExecutionException, InterruptedException {
            List<Integer> list = new ArrayList<>();
            for (int i = 1; i < 101; i++) {
                list.add(i);
            }
            ForkAndJoinRequest request = new ForkAndJoinRequest(0, list.size() - 1, list);
            forkJoinPool.submit(request);
            System.out.println(request.get());
        }
    
    
    }
    
    //定义request继承RecursiveTask,并实现compute方法
    class ForkAndJoinRequest extends RecursiveTask<Integer> {
    
        private int start;
        private int end;
        private List<Integer> list;
    
        public ForkAndJoinRequest(int start, int end, List<Integer> list) {
            this.start = start;
            this.end = end;
            this.list = list;
        }
    
        @Override
        protected Integer compute() {
            int count = end - start;
            if (count <= 25) { //如果需要累加的数量小于等于25,则直接执行
                int result = 0;
                for (int i = start; i <= end; i++) {
                    result += i;
                }
                return result;
            } else { //否则fork出其他request
                int mid = (start + end) / 2;
                ForkAndJoinRequest request1 = new ForkAndJoinRequest(start, mid, list);
                request1.fork(); //调用fork方法将自身放入等待队列中等待执行
                ForkAndJoinRequest request2 = new ForkAndJoinRequest(mid + 1, end, list);
                request2.fork();
    
                //等待执行结果
                return request1.join() + request2.join();
    
            }
        }
    }

      

    ForkJoin实现思路:

      每个Worker线程都维护一个任务队列,即ForkJoinWorkerThread中的任务队列

      任务队列是双向队列,这样可以同时实现LIFO和FIFO

      子任务会被加入到原先任务所在Worker线程的任务队列

       Work线程使用LIFO的方法取出任务,后进队列的任务先取出来(子任务需要先执行)

       当任务队列为空,会随机从其他Worker的队列中拿走一个任务执行(工作窃取)

       如果一个Worker线程遇到了join操作,而这时正在处理其他任务,会等到这个任务执行结束,否则立刻返回

       如果一个Worker线程窃取任务失败,它会调用yield或者sleep方法休息一会再尝试。如果所有线程都是等待状态,那么此线程业务

    阻塞直到新任务的到来

       

    ForkJoinPool适用情况:

       使用尽可能少的线程池--在大多数情况下,最好的决定是为每个应用程序或者系统使用一个线程池。

       如果不需要特定调整,请使用默认的公共线程池。ForkJoinPool默认会产生CPU个数的线程

       使用合理的阈值将ForkJoinTask拆分为子任务

       避免在ForkJoinTask中出现任何阻塞。所以文件操作,http接口调用等场景不建议使用

       适合数据处理、结果汇总、统计等场景

       java8实例:java.util.Arrays类用于其parallelSort()方法

  • 相关阅读:
    Java生成二维码连接
    Spring boot 整合 Elasticsearch
    Windows下安装ElasticSearch
    springcloud zookeeper+gateway
    idea中Springcloud同时运行多个模块、微服务
    【转】为什么我的DIV块前总有空隙?
    【转载】通过JSFL让Flash Professional CS4或CS5拥有批量FLA导出SVG的功能
    jQuery Mobile中的页面加载与跳转机制
    关于Conversion to Dalvik format failed with error 1错误
    带权重的随机输出数组中的元素
  • 原文地址:https://www.cnblogs.com/wkzhao/p/10263753.html
Copyright © 2020-2023  润新知