java forkjoin MySQL_手把手教你 Fork/Join 并发处理

ForkJoinPool 是 Java 7 加入的一个并发处理类,位于 java.util.concurrent 包。

Fork / Join 回顾

ForkJoinPool 让我们可以很方便地把任务分裂成几个更小的任务,这些分裂出来的任务也将会提交给 ForkJoinPool。任务可以继续分割成更小的子任务,只要它还能分割。分叉和合并原理包含两个递归进行的步骤。两个步骤分别是分叉步骤和合并步骤。

一个使用了分叉和合并原理的任务可以将自己分叉(分割)为更小的子任务,这些子任务可以被并发执行。如下图所示:

4d76a3f4cc6f?from=singlemessage

通过把自己分割成多个子任务,每个子任务可以由不同的 CPU 并行执行,或者被同一个 CPU 上的不同线程执行。

只有当给的任务过大,把它分割成几个子任务才有意义。把任务分割成子任务有一定开销,因此对于小型任务,这个分割的消耗可能比每个子任务并发执行的消耗还要大。

什么时候把一个任务分割成子任务是有意义的,这个界限也称作一个阀值。这要看每个任务对有意义阀值的决定。很大程度上取决于它要做的工作的种类。

当一个任务将自己分割成若干子任务之后,该任务将等待所有子任务结束。一旦子任务执行结束,该任务可以把所有结果合并到同一个结果。图示如下:

4d76a3f4cc6f?from=singlemessage

Fork / Join 的使用

Fork / Join 的使用主要涉及 ForkJoinPool 和 ForkJoinTask。ForkJoinTask 类定义了任务,实现了 Fork 和 Join 操作;ForkJoinPool 管理线程与任务的执行。

ForkJoinTask 类是一个抽象类,要求子类实现以下三个方法:

getRawResult :获取 ForkJoinTask 的执行结果;

setRawResult :设置 ForkJoinTask 的执行结果;

exec :ForkJoinTask 的执行逻辑,返回 true 表示正常返回;

为了方便开发,标准库提供了 ForkJoinTask 的一个子类 RecursiveTask。RecursiveTask 类也是一个抽象类,封装了上述 3 个方法的实现,要求子类实现一个方法 compute。这样一来,我们只需要实现 compute 一个方法就可以使用 ForkJoinTask 了。RecursiveTask 的定义如下:

public abstract class RecursiveTask extends ForkJoinTask {

private static final long serialVersionUID = 5232453952276485270L;

V result;

protected abstract V compute();

public final V getRawResult() {

return result;

}

protected final void setRawResult(V value) {

result = value;

}

protected final boolean exec() {

result = compute();

return true;

}

}

以计算数组所有数字的和为例,我们定义一个 Task 类继承 RecursiveTask,在 compute 方法中把数组一分为二,创建两个 Task 实例,分别调用 fork 方法,再分别调用 join 方法获取两个 Task 的计算结果,从而得到数组所有数字的和。

public class Task extends RecursiveTask {

private static final long serialVersionUID = 1L;

long[] data;

int start;

int end;

public Task(long[] data, int start, int end) {

this.data = data;

this.start = start;

this.end = end;

}

@Override

protected Long compute() {

long sum = 0;

if(end - start < 1000){

for(int i = start; i <= end; i++){

sum += data[i];

}

}else {

//分割任务

int middle = (start + end) / 2;

Task left = new Task(data,start,middle);

Task right = new Task(data,middle + 1,end);

left.fork();//fork 操作

right.fork();//fork 操作

sum = left.join() + right.join();//join操作

}

return sum;

}

}

使用 ForkJoinPool 的方法很简单,创建 ForkJoinPool 实例,然后调用 invoke 方法执行 ForkJoinTask 任务即可获得计算结果。

long[] data = new long[1024*1024];

Arrays.setAll(data, i -> i);

long sum = new ForkJoinPool().invoke(

new Task(data, 0, data.length - 1)

);

System.out.println(sum);

如果不需要获取计算的结果,比如需要执行一些没有返回值的操作,也可以调用 execute 方法。

每周 3 篇学习笔记或技术总结,内容涉及 Java 进阶、虚拟机、MySQL、NoSQL、分布式计算、开源框架等多个领域。关注作者或微信公众号 后端开发那点事儿 第一时间获取最新内容。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值