Fork / Join 框架

Fork-Join框架的用途:

将一个庞大的任务,拆分成多个互不相关的子任务,分别执行,并汇总结果,得到最终结果。

什么是分而治之?

规模为N的问题,N<阈值,直接解决,N>阈值,将N分解为K个小规模子问题,子问题互相对立,与原问题形式相同,将子问题的解合并得到原问题的解。

有3个父类:

  1. RecursiveTask (有返回值的任务父类)
  2.  RecursiveAction (无返回值任务的父类)
  3. ForkJoinTask(1,2的父类)

 示例:

  1. 同步等待结果返回
    ForkJoinPool.invoke

求解一个Int数组的和:

public class MyArray {
    public static int arrSize = 1000;

    public static Integer[] initArr() {
        Integer[] arr = new Integer[arrSize];
        Random random = new Random();
        for (int i = 0; i < arrSize; i++) {
            arr[i] = random.nextInt(arrSize * 4);
        }
        return arr;
    }
}

普通方法求和

public class SumNormal {
    public static void main(String[] args) throws InterruptedException {
        Integer[] arr = MyArray.initArr();
        long startTime = System.currentTimeMillis();
        int result = 0;
        for (int i = 0; i < arr.length; i++) {
            result += arr[i];
            Thread.sleep(1);
        }
        System.out.println("The count is "+result
                +" spend time:"+(System.currentTimeMillis()-startTime)+"ms");
    }
}

运行结果:

The count is 2008834 spend time:1039ms

Fork Join拆分方法求和

public class SumForkJoin {
    //继承RecursiveTask实现Fork Join框架
    private static class ForkJoinImpl extends RecursiveTask<Integer> {
        private final static int THRESHOLD = MyArray.arrSize / 10;
        Integer[] src;
        int fromIndex;
        int toIndex;

        public ForkJoinImpl(Integer[] src, int fromIndex, int toIndex) {
            this.src = src;
            this.fromIndex = fromIndex;
            this.toIndex = toIndex;
        }

        //必须重写的方法
        @Override
        protected Integer compute() {
            if (toIndex - fromIndex < THRESHOLD) {
                int count = 0;
                for (int i = fromIndex; i <= toIndex; i++) {
                    count += src[i];
                }
                return count;
            } else {
                int mid = (fromIndex + toIndex) / 2;
                ForkJoinImpl left = new ForkJoinImpl(this.src, this.fromIndex, mid);
                ForkJoinImpl right = new ForkJoinImpl(this.src, mid, this.toIndex);
                //递归调用所有RecursiveTask子类的compute
                invokeAll(left, right);
                //join获取RecursiveTask子类的结果
                return left.join() + right.join();
            }
        }
    }

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        Integer[] arr = MyArray.initArr();
        long startTime = System.currentTimeMillis();
        ForkJoinImpl impl = new ForkJoinImpl(arr, 0, arr.length - 1);
        pool.invoke(impl);//同步方法
        System.out.println("Task is Running.....");

        System.out.println("The count is "+impl.join()
                +" spend time:"+(System.currentTimeMillis()-startTime)+"ms");
    }
}

运行结果:

Task is Running.....
The count is 2010582 spend time:9ms

根据结果对比,当任务需要花费时间时,可以发现串行任务比Fork-Join所花费的时间长.但是也不一定ForkJoin的时间就比串行时间段,因为ForkJoin底层实现为递归,所以存在上下文调度。

2. 异步返回没有结果

ForkJoinPool.execute

查询文件夹下的所有txt文件

public class FileSeacherForkJoin {
    private static String file_suffix = "txt";

    private static class FileSearchForkJoinImpl extends RecursiveAction {
        File file;

        public FileSearchForkJoinImpl(File file) {
            this.file = file;
        }

        @Override
        protected void compute() {
            if (file.isDirectory()) {
                List<FileSearchForkJoinImpl> list = new ArrayList<>();
                File[] files = file.listFiles();
                for (File file : files) {
                    if(file.isDirectory()){
                        list.add(new FileSearchForkJoinImpl(file));
                    }else{
                        if (file.getAbsolutePath().endsWith(file_suffix)) {
                            System.out.println("文件:" + file.getAbsolutePath());
                        }
                    }
                }
                if (!list.isEmpty()){
                    for (FileSearchForkJoinImpl impl : invokeAll(list)){
                        impl.join();
                    }
                }
            } else {
                if (file.getAbsolutePath().endsWith(file_suffix)) {
                    System.out.println("文件:" + file.getAbsolutePath());
                }
            }
        }
    }

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        File file = new File("E:\\tomcat\\apache-tomcat-7.0.59");
        FileSearchForkJoinImpl impl = new FileSearchForkJoinImpl(file);
        pool.execute(impl);//异步执行没有返回值
        System.out.println("main task is end");
        impl.join();//阻塞
        System.out.println("all task is done");
    }
}

运行结果:

main task is end
文件:E:\tomcat\apache-tomcat-7.0.59\RUNNING.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-04-29.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-07-22.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-08-22.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-08-23.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-08-24.txt
文件:E:\tomcat\apache-tomcat-7.0.59\logs\localhost_access_log.2015-08-25.txt
all task is done

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值