java的ForkJoinPool
最近在看线程池代码时发现了一个ForkJoinPool类,可以看一下线程池的继承关系,顶层的Executor接口,提供了一个execute()方法,我们常用的ExecutorService接口也继承自Executor接口,定义了一些额外的方法,下面呢就是AbstractExecutorService类,在这个类中实现了三个submit方法,而创建线程池的ThreadPoolExecutor类就继承自AbstractExecutorService,而同时ForkJoinPool也继承了AbstractExecutorService,对于这个ForkJoinPool以往不太了解,简单学习了一下进行记录。下面是线程池继承体系。
ForkJoin并发框架是一个用于并行执行任务的框架,适用于计算密集型,它可以把一个任务分成若干个小任务,也可以把各个小任务的结果进行合并,所以很适合计算如从1加到100000这种操作。
ForkJoin并发框架:fork 分解任务 +join 将结果合并,当然,对于一些没有返回结果的任务,可以只fork不合并。也就是仅仅fork划分任务,但不join进行任务结果的合并。
java中实现ForkJoin的几个类
ForkJoinPool:继承了线程池的接口,因此也是一种线程池的实现,不同之处在于我们平常创建的线程池只有一个任务队列,而ForkJoinPool可以为每个线程分配任务队列,同时一个线程可以从其他线程的任务队列中获取任务,因为有些线程可以很快的完成了任务,有些可能完成的比较慢,这是,完成快的就可以从完成慢的线程的任务队列中获取任务(从任务队列后端获取)。
ForkJoinTask:也就是ForkJoinPool要完成的任务,提供了fork和join 方法,有两个常用的抽象子类RecursiveTask和RecursiveAction,都提供了抽象方法compute,我们可以重写compute方法进行任务的划分,RecursiveTask提供返回值,而RecursiveAction不提供返回值。
通过一段代码来理解forkjoin的用处和用法,计算从0加到10000000...。
定义一个类继承RecursiveTask
public class ForkJoinCal extends RecursiveTask<Long> { private long start; private long end; private static final long THRESHOLD = 10000L;//临界值 public ForkJoinCal(long start, long end) { this.start = start; this.end = end; } @Override protected Long compute() { long length = end -start; if(length<=THRESHOLD){ long sum =0; for (long i = start; i <=end ; i++) { sum+=i; } return sum; }else { long middle =(start+end)/2; ForkJoinCal left = new ForkJoinCal(start, middle); left.fork(); ForkJoinCal right = new ForkJoinCal(middle + 1, end); right.fork(); return left.join()+right.join(); } } }
主方法进行测试
public class ForkJoinTest { public static void main(String[] args) { ForkJoinPool pool = new ForkJoinPool(2); ForkJoinCal task = new ForkJoinCal(0, 1000000000L); Long sum = pool.invoke(task); System.out.println(sum); } }
本文暂时使了解ForkJoin是什么,怎么用,下面会对一些原理进行分析。