深入理解并发编程之线程池Fork Join
文章目录
一、什么是Fork Join
或许初级程序员不知道什么是Fork Join,我们先简单的举个例子来说明下:
Fork Join是Java7提供的并行执行任务的框架,是一个把大任务分割成若干小任务,小任务可以继续不断拆分n多个小任务,最终汇总小任务的结果得到大任务结果的框架。
二、举例说明下Fork Join的用法
我们用3个线程的Fork Join线程池求1到10W的和来简单的看一下:
public class ForkJoinTest extends RecursiveTask<Long> {
private Long start; //计算的开始值
private Long end; //计算的最终值
private Long max = 100L; //计算区间的最大差值
private static AtomicInteger worker1 = new AtomicInteger(0); //分别记录每个线程执行次数
private static AtomicInteger worker2 = new AtomicInteger(0);
private static AtomicInteger worker3 = new AtomicInteger(0);
public ForkJoinTest(Long start, Long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
Long sum = 0L;
//如果计算的区间小于100直接计算
if (end - start < max) {
if ("ForkJoinPool-1-worker-1".equals(Thread.currentThread().getName())) {
worker1.incrementAndGet(); //如果线程1执行就++
System.out.println("worker1:" + worker1.get());
}
if ("ForkJoinPool-1-worker-2".equals(Thread.currentThread().getName())) {
worker2.incrementAndGet(); //如果线程2执行就++
System.out.println("worker2:" + worker2.get());
}
if ("ForkJoinPool-1-worker-3".equals(Thread.currentThread().getName())) {
worker3.incrementAndGet(); //如果线程3执行就++
System.out.println("worker3:" + worker3.get());
}
for (Long i = start; i <= end; i++) {
sum += i;
}
} else {
// 如果计算的区间>=100,分两半继续分直到分的区间小于100为止
Long l = (start + end) / 2;
ForkJoinTest left = new ForkJoinTest(start, l); //执行前面的一半
//Fork()方法 Fork()方法类似于Thread.start(),但是它并不立即执行任务,而是将任务放入工作队列中,拆分子任务。
left.fork();
ForkJoinTest rigt = new ForkJoinTest(l + 1, end); //执行后面的一半
rigt.fork();
try {
sum = left.get() + rigt.get(); //每一半的最终结果加起来
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
return sum;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ForkJoinTest forkJoinTest = new ForkJoinTest(1L, 10000L);
ForkJoinPool forkJoinPool = new ForkJoinPool(3); //线程池有3个线程
ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinTest);
System.out.println("执行结果为:" + submit.get());
}
}
可以看一下计算结果:
不考虑线程的话我们仔细看一下上面代码的逻辑,其实就是一个递归操作,我们一直往下递归把10000拆分成每部分都区间小于100的多个部分进行计算,然后把最后的和汇总起来。其实Fork Join就是使用多线程的递归,首先设置个预期值,如果在预期值内直接执行,如果不在预期值内则继续递归,往下继续递归任务。
Fork Join有三种提交任务的方式:
- 通过invoke方法提交的任务,调用线程直到任务执行完成才会返回,也就是说这是一个同步方法,且有返回结果;
- 通过execute方法提交的任务,调用线程会立即返回,也就是说这是一个异步方法,且没有返回结果;
- 通过submit方法提交的任务,调用线程会立即返回,也就是说这是一个异步方法,且有返回结果(返回Future实现类,可以通过get获取结果
内容来源:蚂蚁课堂