并发编程之Fork/Join

一。概览

1.fork/join体现了“分而治之”,框架的原理也是分而治之,就是将一个大任务,进行拆分成若干个小任务,再将一个个的小任务运算的结果进行join汇总
  所谓的分而治之是:一个大问题分割成多个相同的小问题,并且小问题之间无关联
  对应的动态规划是:一个大问题分割成多个相同的小问题,并且小问题之间有关联
	
2.fork/join使用标准范式:  
	1.new ForkJoinPool   
	2.new MyTask或者MyAction   task继承RecursiveTask<Integer> action继承RecursiveAction 
	3.pool.invoke(task);

3.fork/join使用说明
	需要返回值的用Task 不需要返回值的用Action  标准范式第二步骤   Task继承RecursiveTask<Integer>   Action继承RecursiveAction
	同步用invoke,异步用submit或者execute    标准范式第三步骤

二。案例

1. 统计整型数组中所有元素的和
常规做法:单线程遍历累加
public class SumNormal {	
	public static void main(String[] args) {
	    int count = 0;
	    int[] src = MakeArray.makeArray();

	    long start = System.currentTimeMillis();
	    for(int i= 0;i<src.length;i++){
			SleepTools.ms(1);
	    	count = count + src[i];
	    }
	    System.out.println("The count is "+count
	            +" spend time:"+(System.currentTimeMillis()-start)+"ms");		
	}
}
fork/join多线程做法: 
1.定义fork/join任务重写compute()方法(因为有返回值所以是Task,无返回值action)
private static class SumTask extends RecursiveTask<Integer>{
        /*阈值 拆分的最小单位 大于这个值继续拆分,否则不用再拆分*/
        private final static int THRESHOLD = MakeArray.ARRAY_LENGTH/10;
        private int[] src;
        private int fromIndex;
        private int toIndex;
		//构造函数
        public SumTask(int[] src, int fromIndex, int toIndex) {
            this.src = src;
            this.fromIndex = fromIndex;
            this.toIndex = toIndex;
        }

        @Override
        protected Integer compute() {
            /*任务的大小是否合适 不用再拆分*/
            if (toIndex - fromIndex < THRESHOLD){
                System.out.println(" from index = "+fromIndex
                        +" toIndex="+toIndex);
                int count = 0;
                for(int i= fromIndex;i<=toIndex;i++){
                	SleepTools.ms(1);
                     count = count + src[i];
                }
                return count;
            }else{
                //继续拆分
                int mid = (fromIndex+toIndex)/2;
                SumTask left = new SumTask(src,fromIndex,mid);
                SumTask right = new SumTask(src,mid+1,toIndex);
                invokeAll(left,right);
                return left.join()+right.join();
            }
        }
}
2.主线程
public static void main(String[] args) {
		//整型数组
        int[] src = MakeArray.makeArray();
        /*1.标准范式1:new出池的实例*/
        ForkJoinPool pool = new ForkJoinPool();
        /*2.标准范式2:new出Task*/
        SumTask sumTask= new SumTask(src,0,src.length-1);
        /*3.标准范式3:提交*/
        pool.invoke(sumTask); 
           
        System.out.println("The count is "+sumTask.join());
    }
    
/**
 * 工具类:创建一个长度为3000的整型数组
 */
public class MakeArray {
    //数组长度
    public static final int ARRAY_LENGTH  = 3000;
    public final static int THRESHOLD = 47;

    public static int[] makeArray() {

        //new一个随机数发生器
        Random r = new Random();
        int[] result = new int[ARRAY_LENGTH];
        for(int i=0;i<ARRAY_LENGTH;i++){
            //用随机数填充数组
            result[i] =  r.nextInt(ARRAY_LENGTH*3);
        }
        return result;

    }
}
2 遍历指定目录(含子目录)找寻指定类型文件
1.定义fork/join任务重写compute()方法(因为无返回值所以是action,有返回值task)

public class FindDirsFiles extends RecursiveAction {
    private File path;

    public FindDirsFiles(File path) {
        this.path = path;
    }

    @Override
    protected void compute() {
        List<FindDirsFiles> subTasks = new ArrayList<>();

        File[] files = path.listFiles();
        if (files!=null){
            for (File file : files) {
                if (file.isDirectory()) {
                    // 对每个子目录都新建一个子任务。
                    subTasks.add(new FindDirsFiles(file));
                } else {
                    // 遇到文件,检查。
                    if (file.getAbsolutePath().endsWith("txt")){
                        System.out.println("文件:" + file.getAbsolutePath());
                    }
                }
            }
            if (!subTasks.isEmpty()) {
                // 在当前的 ForkJoinPool 上调度所有的子任务。
                for (FindDirsFiles subTask : invokeAll(subTasks)) {
                    subTask.join();
                }
            }
        }
    }
}
2.主线程
    public static void main(String [] args){
        try {
            // 1.标准范式1:new出池的实例
            ForkJoinPool pool = new ForkJoinPool();
            //2.标准范式2:new出任务
            FindDirsFiles task = new FindDirsFiles(new File("F:/"));
            /*3.标准范式2:异步提交  同步用invoke*/
            pool.execute(task);

            /*主线程做自己的业务工作*/
            System.out.println("Task is Running......");
            Thread.sleep(1);
            int otherWork = 0;
            for(int i=0;i<100;i++){
                otherWork = otherWork+i;
            }
            System.out.println("Main Thread done sth......,otherWork="
                    +otherWork);
            task.join();//阻塞方法
            System.out.println("Task end");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飘然生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值