forkjoin分而治之

1.什么是Fork/join框架?
从JDK1.7开始,Java提供Fork/Join框架用于并行执行任务。它的思想就是讲一个大任务分割成若干小任务,最终汇总每个小任务的结果得到这个大任务的结果。如下图:分而治之思想2.什么是分而治之思想可以简单的理解为:将规模为N的问题,当N<阈值,直接解决;当N>阈值,将N分解为K个小规模子问题,子问题互相对立,与原问题形式相同,将子问题的解合并得到原问题的解。3. 工作窃取(work-stealing)在这里插入图片描述假如我们需要做一个比较大的任务,我们可以把这个任务分割为若干互不依赖的子任务,为了减少线程间的竞争,于是把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应,比如A线程负责处理A队列里的任务。如果现场A的任务执行完成后,于是它就去其他线程B的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行,也就是线程B从头部拿取,而线程A从尾部获取任务开始执行。工作窃取算法的优点是充分利用线程进行并行计算,并减少了线程间的竞争,其缺点是在某些情况下还是存在竞争,比如双端队列里只有一个任务时。并且消耗了更多的系统资源,比如创建多个线程和多个双端队列。4.如何实现Fork/joinjava 的ForkJoinTask 抽象类中提供compute方法给我们实现这种思想。java又提供两个抽象类继承ForkJoinTask ,分别是RecursiveAction和RecursiveTask.他们的区别在于:RecursiveTask有返回值,RecursiveAction无返回值。4.1 fork/join标准规范在这里插入图片描述4.2 RecursiveTask的有返回值实现:接下来我们以这样的例子,Fork/Join的同步用法实现有返回结果值:统计整形数组中所有元素的和public class SumArray { private static class SumTask extends RecursiveTask{ 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++) { 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();//任务结果返回 } } } public static void main(String[] args) { //ForkJoinPool 是ExecutorService的实现类,负责工作线程的管理、任务队列的维护,以及控制整个任务调度流程; 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…”); //join方法是返回任务的结果 System.out.println(“The count is “+innerFind.join() +” spend time:”+(System.currentTimeMillis()-start)+“ms”); }}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051524.2 RecursiveAction的无返回值实现:例子是Fork/Join的异步用法不要求返回值,控制台打印结果:遍历指定目录(含子目录)寻找指定txt结尾的文件public class FindDirsFiles extends RecursiveAction{ private File path;//当前任务需要搜寻的目录 public FindDirsFiles(File path) { this.path = path; } 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) { e.printStackTrace(); } } @Override protected void compute() { List 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)) { subTask.join();//等待子任务执行完成 } } } }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354以上就是Fork/Join的简单实现分而治之思想。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值