ForkJoinTask任务框架简介

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Stubborn_Cow/article/details/78774682

ForkJoinTask是jdk1.7整合Fork/Join,即拆分fork+合并join,性能上有大大提升。
思想:充分利用多核CPU把计算拆分成多个子任务,并行计算,提高CPU利用率大大减少运算时间。有点像,MapReduce思路感觉大致一样。
jdk7中已经提供了最简洁的接口,让你不需要太多时间关心并行时线程的通信,死锁问题,线程同步。
主要技术点
1,ForkJoinTask
     主要使用的方法:
     fork()方法:将任务放入队列并安排异步执行
     join()方法:等待计算完成并返回计算结果。
2,ForkJoinPool
     作为对 Fork/Join 型线程池的实现,是ExecutorService的实现类,因此是一种特殊的线程池。创建ForkJoinPool实例后,可以调用ForkJoinPool的submit(ForkJoinTask<T> task)或者invoke(ForkJoinTask<T> task)来执行指定任务。

注:
ForkJoinPool 相比于 ThreadPoolExecutor,还有一个非常重要的特点(优点)在于,ForkJoinPool具有 Work-Stealing (工作窃取)的能力。所谓 Work-Stealing,在 ForkJoinPool 中的实现为:线程池中每个线程都有一个互不影响的任务队列(双端队列),线程每次都从自己的任务队列的队头中取出一个任务来运行;如果某个线程对应的队列已空并且处于空闲状态,而其他线程的队列中还有任务需要处理但是该线程处于工作状态,那么空闲的线程可以从其他线程的队列的队尾取一个任务来帮忙运行 —— 感觉就像是空闲的线程去偷人家的任务来运行一样,所以叫 “工作窃取”

Work-Stealing 的适用场景是不同的任务的耗时相差比较大,即某些任务需要运行较长时间,而某些任务会很快的运行完成,这种情况下用 Work-Stealing 很合适;但是如果任务的耗时很平均,则此时 Work-Stealing 并不适合,因为窃取任务时不同线程需要抢占锁,这可能会造成额外的时间消耗,而且每个线程维护双端队列也会造成更大的内存消耗。所以 ForkJoinPool 并不是 ThreadPoolExecutor 的替代品,而是作为对 ThreadPoolExecutor 的补充。
ForkJoinPool 和 ThreadPoolExecutor 都是 ExecutorService(线程池),但ForkJoinPool 的独特点在于:
ThreadPoolExecutor 只能执行 Runnable 和 Callable 任务,而 ForkJoinPool 不仅可以执行 Runnable 和 Callable 任务,还可以执行 Fork/Join 型任务 —— ForkJoinTask —— 从而满足并行地实现分治算法的需要;
ThreadPoolExecutor 中任务的执行顺序是按照其在共享队列中的顺序来执行的,所以后面的任务需要等待前面任务执行完毕后才能执行,而 ForkJoinPool 每个线程有自己的任务队列,并在此基础上实现了 Work-Stealing 的功能,使得在某些情况下 ForkJoinPool 能更大程度的提高并发效率。


RecursiveTask的例子

class PrintTasks extends RecursiveTask<Integer>  {  
  private static final long serialVersionUID = 1L;

  // 每个"小任务"最多只打印4个数  
  private static final int MAX = 4;  

  private int start;  
  private int end;  

  PrintTasks(int start, int end) {  
      this.start = start;  
      this.end = end;  
  }  

  @Override  
  protected Integer compute() {  
	  Integer cnt =0;
      // 当end-start的值小于MAX时候,开始打印  
      if ((end - start) < MAX) {  
          for (int i = start; i < end; i++) {  
        	  cnt += i;  
          }  
      } else {  
          // 将大任务分解成两个小任务  
          int middle = (start + end) / 2;  
          PrintTask left = new PrintTask(start, middle);  
          PrintTask right = new PrintTask(middle, end);  
          // 并行执行两个小任务  
          left.fork();  
          right.fork();  
          cnt = left.join()+right.join();
      }
	return cnt;  
  }  
}  

public class CopyOfForkJoinPoolTest {  

  public static void main(String[] args) throws Exception {  
      // 创建连接池
      ForkJoinPool forkJoinPool = new ForkJoinPool();  
      // 提交可分解的任务  
      Future<Integer> result = forkJoinPool.submit(new PrintTasks(0, 10));
      // 关闭线程池  
      forkJoinPool.shutdown();  
      long endTime = System.currentTimeMillis();
	  System.out.println("result:"+ result.get());
  }  

}  

RecursiveAction 的例子

class PrintTasks extends RecursiveAction {  
  private static final long serialVersionUID = 1L;

  // 每个"小任务"最多只打印4个数  
  private static final int MAX = 4;  

  private int start;  
  private int end;  

  PrintTasks(int start, int end) {  
      this.start = start;  
      this.end = end;  
  }  

  @Override  
  protected void compute() {  
	  Integer cnt =0;
      // 当end-start的值小于MAX时候,开始打印  
      if ((end - start) < MAX) {  
          for (int i = start; i < end; i++) {  
        	  cnt += i;  
          }  
      } else {  
          // 将大任务分解成两个小任务  
          int middle = (start + end) / 2;  
          PrintTask left = new PrintTask(start, middle);  
          PrintTask right = new PrintTask(middle, end);  
          // 并行执行两个小任务  
          left.fork();  
          right.fork();  
          cnt = left.join()+right.join();
      }
  }  
}  

public class CopyOfForkJoinPoolTest {  

  public static void main(String[] args) throws Exception {  
      // 创建连接池
      ForkJoinPool forkJoinPool = new ForkJoinPool();  
      // 提交可分解的任务  
      forkJoinPool.submit(new PrintTasks(0, 10));
      // 关闭线程池  
      forkJoinPool.shutdown();  
  }  
}  

需要注意的是,在执行子任务时,都使用了下面的写法
 // 并行执行两个小任务  
 left.fork();  
 right.fork();  

这么写,是没有问题的,但是关键是效率低这种写法,意思就是A开了两个子任务B、C,但是A需要等待B、C的结果,在结果出来之前,A的线程就是空闲状态。更好的方式是使用invokeAll,将多个子任务作为参数放进该方法,它会保留一个任务让当前线程A来执行,其他任务会fork给其他线程来执行。这样就充分利用了线程池,提高工作效率。


展开阅读全文

5.4.50.定时任务框架入门

07-21

<p style="font-size:14px;">n <span style="font-size:small;">随着国内IT事业的兴起,越来越多的小伙伴也投身到了开发这个相对高薪的行业来。很多同学进入的方式都是零基础通过培训或者看视频自学,在工作一两年后,发现由于自己的基础太薄弱,想进一步提高自己的能力变得非常 困难。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">现在市面上的视频教程,主要有一下两类:第一类是纯理论的,比如框架、算法、虚拟机等;另一类是Demo级别的项目,如各大培训机构的项目课程。从业这么多年,学习了大量的视频教程,也跟很多毕业三年左右的程序员做过交流,但一直没发现一套特别好的教程,能让小伙伴们从零基础一直到高级进阶,持续得到学习。在工作中,他们也反馈,视频教程各种高大上的技术堆砌,而在实际开发中呢,大部分技术都没有用到,就算是用,也完全不是像教程中那么用的。在面试中,你跟夸夸其谈十分钟,面试官一句,请问你在项目中是怎么用这个技术的,在使用的时候有什么问题?遇到这样的问题,大部分同学们都直接熄火,完全不知所措,为啥呢,因为他在项目中根本没有用过这个技术,只是看了文档、视频,只是跟着教程做了Demo。而技术跟业务如何结合,这应该是大部分同学在工作中最薄弱的环节。甚至,有些同学会唯技术论,面对公司的业务,会去抱怨公司用的技术不新,认为业务不重要。但我要纠正的是,技术的出现本来就是为业务服务的,离开业务谈技术那就是耍流氓。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">早在两年前,我就萌生了这样的想法,既然国内的环境造成了面试修地球,上班拧螺丝的情况,那么我能不能结合我自己做的真实项目,脱敏后给大家分享出来,让各位同学能有一个真实的项目环境去边学边提高,所以,也就有了《从0开始用Java做"智慧农业物联网"》课程的诞生。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">学习本课程的基本要求:有Java基础,学习过Spring,SpringMVC,Mybatis框架,做过简单项目以上的同学均可学习。但并不代表,本课程就是个入门教程,对于有开发经验的同学们,物联网这个行业是个朝阳产业,也可以说是未来十年发展的蓝海。那我相信,有实体经济支撑的行业绝不会像互联网行业有那样大的泡沫,也绝不会让你工作的没有安全感。对于有志于从事物联网相关工作的同学,对于想从各方面提升自己的各位同学们来说,本课程也非常的适合你们去学习。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">我从12年就开始接触物联网项目,做过智慧猪场、智慧农场、猪联网、云医疗等相关项目,也做过互联网行业,兜兜转转一圈下来,自认为还是积累了很多的经验和教训,那我都会在我课程中对这样的知识有所分享。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">同时,在这个课程中,我既是产品,又是设计,还是开发,还是运维,也是客户,我会从一个项目的全生命周期给大家进行介绍,并且都有相关的落地方案。这样,同学们的眼光就会有所延展,不会仅仅局限在开发这一亩三分地上。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">本课程的亮点:我只能说,亮点很多,很多。。。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">核心如下:产品经理眼中的产品、数据库设计、如何把一个需求变成代码、如何跟物联网设备交互、如何上线一个项目、在需求变更后如何做到不跟产品撕逼。。。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">看到了吧,我不会只让你知道那些高大上的技术点,我向你们学会的是如何做一个完美的产品!</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">在这个课程中,你会看到太多太多跟其他教程不同的地方,你看到的不是Demo级别的案例,你看到的绝对是一个工业级别的实现方案。我也希望通过这个课程,同学们能进一步升华自己的视界,你所站的高度,你看问题的不同角度,将决定未来你成长的上限。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">对于本课程的成长忠告:本课程的录制会持续很长时间,是的,你没看错,是很长时间,目前我的预期,起码是在年底之前不会结束,为什么要这样安排,因为我想要分享的内容实在太多,我也不想对课程进行拆分,也不想草草结束,所以,你所能得到的收获一定会足够大,他没有终点。。。</span>n</p>n<p style="font-size:14px;">n <span style="font-size:small;">最终达到的效果:在业务中学技术点,通过技术点让业务变得更优美!</span>n</p>

没有更多推荐了,返回首页