Java多线程系列之:线程的并发工具类

一,Fork-Join

1,定义:

Fork-Join框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不能再拆时),再将一个个的小任务运算的结果进行join汇总。

2,,Fork-Join体现了分而治之。什么是分而治之?

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

3,工作密取(workStealing)

4,Fork-Join实战

4.1,Fork/Join的同步调用同时演示返回值结果: 统计整型数组中所有元素的和

/**
 * 产生整型数组工具类
 */
public class MakeArray {

    //数组长度
    public static final int ARRAY_LENGTH = 4000;
    public static int[] makeArray(){
        //new一个随机数发生器
        Random rd = new Random();
        int[] result = new int[ARRAY_LENGTH];
        for (int i = 0; i < ARRAY_LENGTH;i++){
            //用随机数填充数组
            result[i] = rd.nextInt(ARRAY_LENGTH*3);
        }
        return result;
    }
}
/**
 * 使用Fork-Join框架进行计算
 */
public class SumArray {

    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){
                int count = 0;
                for(int i = fromIndex;i <= toIndex;i++){
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count = count + src[i];
                }
                return count;
            }else {
                //fromIndex ..... mid....... toIndex。这里我们自己定义的算法:大于阈值就平均分为两部分
                int mid = (fromIndex + toIndex)/2;
                SumTask left = new SumTask(src,fromIndex,mid);
                SumTask right = new SumTask(src,mid,toIndex);
                invokeAll(left,right);
                return left.join() + right.join();
            }
        }
    }

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        int[] src = MakeArray.makeArray();
        SumTask innerFind = new SumTask(src,0,src.length-1);
        long start = System.currentTimeMillis();
        pool.invoke(innerFind);//同步调用
        System.out.println("Task is Running.......");
        System.out.println("the count is "+ innerFind.join()+" spend time:"+(System.currentTimeMillis()-start)+"ms");
    }

    /**
     * 注意:
     * 对于这种简单的相加操作,其实单线程处理的速度更快。
     * 使用forkjoin后,使用多线程进行处理。由于需要线程间的切换(上下文切换),导致forkjoin的处理方式花的时间更多。
     * 所以使用forkjoin一定要注意场合。
     * 这也是redis虽然使用单进程单线程模式,但是处理能力非常强的原因,就是因为redis处理的数据比较简单(String)。
     * 并且使用单线程处理避免了进程间的切换。
     */
}

4.2,Fork/Join的异步调用同时演示不要求返回值:遍历指定目录(含子目录),寻找指定类型文件

/**
 * 遍历指定目录(含子目录),找寻指定类型文件
 * 不需要返回值的的Fork/Join
 */
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()){

                for (FindDirsFiles subTask:invokeAll(subTasks)){
                    //上面的invlkeAll():用来递交子任务
                    subTask.join();//等待子任务
                }
            }
        }
    }

    public static void main(String[] args) {
        try {
            //用一个ForkJoinPool 实例调度总任务
            ForkJoinPool pool = new ForkJoinPool();
            FindDirsFiles task = new FindDirsFiles(new File("D:\\yishang"));
            pool.execute(task);

            System.out.println("task is running........");

            //主线程做一些自己的事情
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            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){
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/inspred/p/11102934.html