并发编程-ForkJoin【享学】

Fork-Join

java下多线程的开发可以启用多线程,线程池,还可以使用forkjoin, forkjoin 可以让我们不去了解诸如Thread,Runnable 等相关的知识,只要遵循 forkjoin 的开发模式,就可以写出很好的多线程并发程序。

分而治之

forkjoin 在处理分而治之的问题非常有用。十大计算机经典算法:快速排序、堆排序、归并排序、二分查找、线性查找、 深度优先、广度优先、Dijkstra、动态规划、朴素贝叶斯分类,有几个属于分 而治之?3 个,快速排序、归并排序、二分查找,还有大数据中 M/R 都是。 分治法的设计思想是:将一个难以直接解决的大问题,分割成一些规模较小 的相同问题,以便各个击破,分而治之。

分治策略

对于一个规模为 n 的问题,若该问题可以容易地解决(比如说 规模 n 较小)则直接解决,否则将其分解为 k个规模较小的子问题,这些子问题互相独立且与原问题形式相同(子问题相互之间有联系就会变为动态规范算法),递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。

ForkJoin原理

并发编程-ForkJoin【享学】_第1张图片

工作密取

即当前线程的 Task 已经全被执行完毕,则自动取到其他线程的 Task 池中取出 Task 继续执行。
ForkJoinPool 中维护着多个线程(一般为 CPU 核数)在不断地执行 Task,每个线程除了执行自己职务内的 Task 之外,还会根据自己工作线程的闲置情况去获取其他繁忙的工作线程的 Task,如此一来就能能够减少线程阻塞或是闲置的时间,提高 CPU 利用率。
并发编程-ForkJoin【享学】_第2张图片

Fork/Join 使用的标准范式

我们要使用 ForkJoin 框架,必须首先创建一个 ForkJoin 任务。它提供在任务中执行 fork 和 join 的操作机制,通常我们不直接继承 ForkjoinTask 类,只需要直接继承其子类。

  1. RecursiveAction,用于没有返回结果的任务
  2. RecursiveTask,用于有返回值的任务
    task 要通过 ForkJoinPool 来执行,使用 submit 或 invoke 提交,两者的区 别是:invoke 是同步执行,调用之后需要等待任务完成,才能执行后面的代码; submit 是异步执行。
    join()和 get 方法当任务完成的时候返回计算结果。
    并发编程-ForkJoin【享学】_第3张图片
实现1-10000整数的求和计算
public class ForkJoinTest {
	
	public static class SumTask extends RecursiveTask<Integer>{
		
		private int[] intArr;
		private int fromIndex;
		private int toIndex;
		private int threshold;//阈值,当一个任务的执行区间小于阈值时,说明这个任务已经满足最小任务的要求
		
		public SumTask(int[] intArr, int fromIndex, int toIndex, int threshold) {
			this.intArr = intArr;
			this.fromIndex = fromIndex;
			this.toIndex = toIndex;
			this.threshold = threshold;
		}

		//compute ForkJoin的核心方法,进行拆分计算
		@Override
		protected Integer compute() {
			if (toIndex - fromIndex < threshold) {//如果区间小于阈值,任务到达最小任务要求,计算
				int count = 0;
				for(int i = fromIndex;i <= toIndex;i++) {
					count = count + intArr[i];
				}
			return count;
			}else {
				int mid = (fromIndex + toIndex)/2;
				SumTask leftTask = new SumTask(intArr,fromIndex,mid,threshold);
				SumTask rightTask = new SumTask(intArr,mid+1,toIndex,threshold);
				invokeAll(leftTask,rightTask);
				return leftTask.join() + rightTask.join();//join()方法获取计算的值
			}
		}
	}
	//测试方法
	public static void main(String[] args) {
		int[] intArr = IntStream.rangeClosed(1, 10000).toArray();
		ForkJoinPool pool = new ForkJoinPool();
		SumTask sumTask = new SumTask(intArr, 0, intArr.length - 1,intArr.length / 10);
		pool.invoke(sumTask);//同步提交
		System.out.println(sumTask.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()) {
                // 在当前的 ForkJoinPool 上调度所有的子任务。
                for (FindDirsFiles subTask : invokeAll(subTasks)) {
                    subTask.join();
                }
            }
        }
    }

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

            /*异步提交*/
            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();
        }
    }
}

你可能感兴趣的:(Java并发编程)