left join 和left outer join的区别_Java并发编程笔记-JDK内置并行执行框架Fork/Join

Fork/Join由来-分而治之思想

分而治之:对于一个比较复杂的任务,如果可以很自然地将其分解为多个子任务,这些子任务互相独立且与原问题性质相同,递归地处理这些子任务,然后将各个子任务的结果合并得到复杂任务的结果,这种算法就是所谓的分而治之思想。分治法的一般步骤:分解->求解->合并。比如大数据领域的MapReduce计算框架就是采用了分治的思想,首先将输入切割成标准分片,然后对每个分片经过一系列计算处理,最后合并处理结果并输出。

Fork-Join框架

Fork/Join框架:它的主要作用是将一个复杂任务分割成若干个子任务 ,再将一个个的子任务运算的结果进行join汇总,得到最终的结果。

0ff78cafd0a132b2281fb1a748c781bc.png

Fork-Join流程

工作窃取:在实际执行过程中,可能每个子任务的处理速度都不相同,导致出现有的线程会先把自己队列里的任务快速执行完毕,而其他线程对应的队列里还有任务等待处理,工作线程就会尝试去获取其他繁忙的工作线程的任务,如此一来就能够减少线程阻塞或是闲置的时间,提高CPU利用率。

e2f46675bc0799ff7751d45ed2589ad3.png

Fork/Join实战-ForkJoinPool

ForkJoinPool是ExecutorService的实现类,也就是说它是一种特殊的线程池。首先看看ForkJoinPool的类图关系。

9e7e871675e2fbf7e1355fdca9cc7529.png

ForkJoinPool执行任务的对象是ForkJoinTask,它提供在任务中执行fork和join的操作机制。ForkJoinTask提供了2个实现类方便我们使用,我们只需要重写compute方法即可,

  • RecursiveAction,用于没有返回结果的任务
  • RecursiveTask,用于有返回值的任务
21753ad264c9eed844ce8d9ef1e8b6d6.png

ForkJoinPool使用submit或invoke或execute提交任务,两者的区别是:

  • invoke方法:同步执行,调用之后需要等待任务完成,才能执行后面的代码
  • submit方法:异步执行,有返回值
  • execute方法:异步执行,无返回值

使用join或者get方法来获取当任务返回的计算结果。

基本使用-RecursiveAction

/** * 遍历文件,使用RecursiveAction */public class RecursiveActionDemo { public static class RecursiveActionTask extends RecursiveAction { private File file; public RecursiveActionTask(File file) { this.file = file; } @Override protected void compute() { if (file == null) { return; } if (!file.exists()) { return; } if (file.isDirectory()) { for (File listFile : file.listFiles()) { RecursiveActionTask recursiveActionTask = new RecursiveActionTask(listFile); recursiveActionTask.invoke();// recursiveActionTask.fork();// recursiveActionTask.join(); } } else { System.out.println(Thread.currentThread().getName() + ">>>" + file.getAbsolutePath()); } } } public static void main(String[] args) { String filePath = "C:Program FilesJava"; File file = new File(filePath); RecursiveActionTask task = new RecursiveActionTask(file); ForkJoinPool pool = new ForkJoinPool();// ForkJoinPool pool = ForkJoinPool.commonPool(); pool.invoke(task);// pool.execute(task);// task.join(); System.out.println(">>>>>>>>>>>>>>over<<<<<<<<<<<
d9ba0e26fd7db34818be422c1f9de16c.png

基本使用-RecursiveTask

/** * 数组求和,使用RecursiveTask */public class RecursiveTaskDemo { private static class SumTask extends RecursiveTask { private final static int THRESHOLD = 10; private int[] sourceArray; private int left; private int right; public SumTask(int[] sourceArray, int left, int right) { this.sourceArray = sourceArray; this.left = left; this.right = right; } @Override protected Long compute() { //数组一分为2,递归切分,直到小于设定阈值 if (right - left < THRESHOLD) { long count = 0; for (int i = left; i <= right; i++) { count = count + sourceArray[i]; } return count; } else { int mid = (left + right) / 2; SumTask leftTask = new SumTask(sourceArray, left, mid); //注意右边从(mid+1)开始 SumTask rightTask = new SumTask(sourceArray, mid + 1, right); invokeAll(leftTask, rightTask); return leftTask.join() + rightTask.join(); } } } /** * 生成整形数组 * @param length */ private static int[] createArray(int length) { if (length < 0) { return new int[0]; } int[] arr = new int[length]; for (int i = 0; i < length; i++) { arr[i] = i; } return arr; } public static void main(String[] args) { int[] src = createArray(10000000); long start = System.currentTimeMillis(); ForkJoinPool pool = new ForkJoinPool(); SumTask task = new SumTask(src, 0, src.length - 1); pool.invoke(task); System.out.println("sum = " + task.join() + " 耗时:" + (System.currentTimeMillis() - start) + "ms"); }}
6c795dca80b36abe63eb46f629e4eaf7.png

ForkJoinPool比较适合计算密集型任务,使用ForkJoinPool并不一定就比单线程要快,实际使用时请综合考虑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值