jdk并发工具类: Fork&Join框架

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010391342/article/details/82155246

Fork -join框架

叉/加入框架是JAVA7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架
其思想和MapReduce的的思想非常类似。对于任务的分割,要求各个子任务之间相互独立,能够并行独立地执行任务,互相之间不影响。

ForkJoinPool

ForkJoinPool是ForkJoin框架中的任务调度器,和ThreadPoolExecutor的一样实现了自己的线程池,提供了三种调度子任务的方法:

execute:异步执行指定任务,无返回结果;
invoke、invokeAll:异步执行指定任务,等待完成才返回结果;
submit:异步执行指定任务,并立即返回一个Future对象;

fork-join框架中的实际的执行任务类,有以下两种实现,一般继承这两种实现类即可。
RecursiveAction:用于无结果返回的子任务;
RecursiveTask:用于有结果返回的子任务;

有返回结果的任务

package com.example.lock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

import com.alibaba.fastjson.JSONObject;

public class ForkJoinTask2 extends RecursiveTask<List<JSONObject>>{
    private static final long serialVersionUID = 1L;


    //任务切割阈值
    private static final int THRESHOLD =5;
    private   int start;
    private   int end;
    private  List<JSONObject> list;

    public ForkJoinTask2(int start,int end,List<JSONObject> list){
        this.start=start;
        this.end=end;
        this.list=list;
    }

    @Override
    protected List<JSONObject> compute() {
    System.out.println("进入并行任务处理方法...........................");
       List<JSONObject> lists=new ArrayList<JSONObject>();
        //首先需要判断任务是否小于等于阈值1000  ,如果是就直接执行任务。
        if(end-start<=THRESHOLD){
            for (int i = start; i <=end; i++){
                lists.add(list.get(i));
            }
            System.out.println(Thread.currentThread().getName()+"处理  "+start+"到"+end+"页的数据处理任务");
            return lists;
        }else{
            /**
             * 否则分割成两个子任务
             * 每个子任务在调用fork方法时,又会进入compute方法,看看当前子任务是否需要继续分割成子任务,
             * 如果不需要继续分割,则执行当前子任务并返回结果。使用join方法会阻塞并等待子任务执行完并得到其结果。
             */
            int mid=(start+end)/2;
            ForkJoinTask2 task1=new ForkJoinTask2(start, mid,list);
            task1.fork();

            ForkJoinTask2 task2=new ForkJoinTask2(mid+1, end,list);
            task2.fork();
            lists.addAll(task1.join());
            lists.addAll(task2.join());


            return lists;

        }

    }
     public static void main(String[] args) {
         long start=System.currentTimeMillis();
         ForkJoinPool poll=new ForkJoinPool();
         List<JSONObject> listCount=new ArrayList<>();
         for (int i = 0; i <=20; i++) {
             JSONObject obj= new JSONObject();
              obj.put("id", i);
              listCount.add(obj);
         }
         System.out.println("数据总大小"+listCount.size());
         List<JSONObject> sumList=poll.invoke(new ForkJoinTask2(0, 19,listCount));

         System.out.println("并行处理返回结果:"+sumList.size());
         sumList.forEach(System.out::println);
         System.out.println(System.currentTimeMillis()-start+"ms");
    }



}

无返回值的任务

public class RaskDemo extends RecursiveAction {

     /**
     *  每个"小任务"最多只打印20个数
      */
    private static final int MAX = 5;

    private int start;
    private int end;
    private List<String> list;
    public RaskDemo(int start, int end,List<String> list) {
        this.start = start;
        this.end = end;
        this.list=list;
    }

    @Override
    protected void compute() {
        //当end-start的值小于MAX时,开始打印
        if((end-start) < MAX) {
            for(int i= start; i<end;i++) {
                System.out.println(Thread.currentThread().getName()+"list.get(i);的值"+list.get(i));
            }
        }else {
            System.out.println("任务拆分执行");
            // 将大任务分解成两个小任务
            int middle = (start + end) / 2;
            RaskDemo left = new RaskDemo(start, middle,list);
            RaskDemo right = new RaskDemo(middle, end,list);
            left.fork();
            right.fork();
        }
    }

    public static void main(String[] args) throws InterruptedException {
         // 创建包含Runtime.getRuntime().availableProcessors()返回值作为个数的并行线程的ForkJoinPool
        List<String> lists=Arrays.asList("1","2","3","4","5","6","7","8","9","10","11","12","13","14","15");
        ForkJoinPool forkJoinPool = new ForkJoinPool();

        // 提交可分解的PrintTask任务
        forkJoinPool.submit(new RaskDemo(0, lists.size(),lists));

        //阻塞当前线程直到 ForkJoinPool 中所有的任务都执行结束
//        forkJoinPool.awaitTermination(2, TimeUnit.SECONDS);

        // 关闭线程池
//        forkJoinPool.shutdown();
        forkJoinPool.awaitTermination(30, TimeUnit.SECONDS);
        System.out.println("dadasdsa");


    }
}

在jdk1.8中的并行流就是for join的实现原理

.fork-Join框架与传统线程池的区别:

采用 “工作窃取”模式(work-stealing):当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。

相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态,

而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程的等待时间,提高了性能。

猜你喜欢

转载自blog.csdn.net/u010391342/article/details/82155246