}
@Override
protected void compute() {
if (workload.length() > THRESHOLD) {
// 任务拆分
ForkJoinTask.invokeAll(createSubtasks());
} else {
// 执行业务逻辑
processing(workload);
}
}
private List<CustomRecursiveAction> createSubtasks() {
List<CustomRecursiveAction> subtasks = new ArrayList<>();
String partOne = workload.substring(0, workload.length() / 2);
String partTwo = workload.substring(workload.length() / 2, workload.length());
subtasks.add(new CustomRecursiveAction(partOne));
subtasks.add(new CustomRecursiveAction(partTwo));
return subtasks;
}
private void processing(String work) {
String result = work.toUpperCase();
logger.info("This result - (" + result + ") - was processed by "
+ Thread.currentThread().getName());
}
在这个示例中,我们使用了一个字符串类型 ( String ) 的名为 workload 属性来表示要处理的工作单元。同时,为了演示 Fork/Join 框架的 fork 行为,在该示例中,如果 workload.length() 大于指定的阈值,那么就使用 createSubtask() 方法拆分任务。
在createSubtasks() 方法中,输入的字符串被递归地划分为子串,然后创建基于这些子串的 CustomRecursiveTask 实例。
当递归分割字符串完毕时,createSubtasks() 方法返回 List 作为结果。然后在compute() 方法中使用 invokeAll() 方法将任务列表提交给 ForkJoinPool 线程池。
##### RecursiveTask 使用示例
对于有返回值的任务,除了将每个子任务的结果在一个结果中合并,其它逻辑和 RecursiveAction 都差不多。
public class CustomRecursiveTask extends RecursiveTask {
private int[] arr;
private static final int THRESHOLD = 20;
public CustomRecursiveTask(int[] arr) {
this.arr = arr;
}
@Override
protected Integer compute() {
if (arr.length > THRESHOLD) {
// 任务拆分
return ForkJoinTask.invokeAll(createSubtasks())
.stream()
.mapToInt(ForkJoinTask::join)
.sum();
} else {
// 执行业务逻辑
return processing(arr);
}
}
private Collection createSubtasks() {
List dividedTasks = new ArrayList<>();
dividedTasks.add(new CustomRecursiveTask(
Arrays.copyOfRange(arr, 0, arr.length / 2)));
dividedTasks.add(new CustomRecursiveTask(
Arrays.copyOfRange(arr, arr.length / 2, arr.length)));
return dividedTasks;
}
private Integer processing(int[] arr) {
return Arrays.stream(arr)
.filter(a -> a > 10 && a < 27)
.map(a -> a * 10)
.sum();
}
在上面这个示例中,任务由存储在 CustomRecursiveTask 类的 arr 字段中的数组表示。createSubtask() 方法递归地将任务划分为较小的工作,直到每个部分小于阈值。
然后,invokeAll()方法将子任务提交给公共拉取并返回 Future 列表。
要触发执行,需要为每个子任务调用 join() 方法。
上面这个示例中,我们使用了 Java 8 的流 ( Stream ) API , sum() 方法用于将子结果组合到最终结果中。
##### 将任务提交到 ForkJoinPool 线程池中
只要使用很少的方法,就可以把任务提交到 ForkJoinPool 线程池中。
###### submit()或execute()方法
这两个方法的调用方式是相同的
forkJoinPool.execute(customRecursiveTask);
int result = customRecursiveTask.join();
###### 使用invoke()方法fork任务并等待结果,不需要任何手动连接(join)
int result = forkJoinPool.invoke(customRecursiveTask);
###### invokeAll()方法
将ForkJoinTasks序列提交给ForkJoinPool的最方便的方法它将任务作为参数(两个任务,varargs或集合),fork它们,并按照生成它们的顺序返回Future对象的集合。
###### 使用单独的fork()和join()方法
fork() 方法将任务提交给线程池,但不会触发任务的执行;join() 方法则用于触发任务的执行。在 RecursiveAction 的情况下,join() 返回 null,但对于 RecursiveTask ,它返回任务执行的结果。
customRecursiveTaskFirst.fork();
result = customRecursiveTaskLast.join();
上面的RecursiveTask 示例中,我们使用 invokeAll() 方法向线程池提交一系列子任务。同样的工作,也可以使用 fork() 和 join() 来完成,但这可能会对结果的排序产生影响。
为了避免混淆,当涉及到多个任务且要保证任务的顺序时,通常都是使用 ForkJoinPool.invokeAll()。
### 最后
看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面
小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>
![image](https://img-blog.csdnimg.cn/img_convert/c3c7728db7d8945711c967cc66db8706.webp?x-oss-process=image/format,png)
针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺
![image](https://img-blog.csdnimg.cn/img_convert/c0ec97508e4f888cf87bc2f5e85ea869.webp?x-oss-process=image/format,png)
> 全都是一丢一丢的收集整理纯手打出来的
更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~
![image](https://img-blog.csdnimg.cn/img_convert/74a78b0050974b84d067c420fab6a2c4.webp?x-oss-process=image/format,png)
![image](https://img-blog.csdnimg.cn/img_convert/25737890ec9f8c0d66315f83a9637bcf.webp?x-oss-process=image/format,png)
Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~
[外链图片转存中...(img-3UeGb3nn-1714557759684)]
[外链图片转存中...(img-UcYEt5zy-1714557759685)]
> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/topics/618154847)收录**