Java 中 Fork/Join 框架和 ExecutorService 的区别
在 Java 的并发编程领域,开发者拥有众多选择。Fork/Join 框架和 ExecutorService 是其中两种备受欢迎的方案。尽管这两种解决方案都能很好地实现操作并行化,但它们在针对不同用例需求的结构方面有所不同。通过本文对每个框架的语法特性以及实际代码示例的深入分析,用户可以更好地理解它们之间的区别,以及各自的优势。
语法
Fork/Join 框架
class ForkJoinTask<V> extends Object
ExecutorService
interface ExecutorService extends Executor
语法解释
Fork/Join 框架围绕 ForkJoinTask 类构建,该类表示可以分解成更小子任务的任务。参与该程序将为您提供学习任务递归分解以及如何并发执行它们的机会。此外,通过使用建立在 Executor 接口之上的 ExecutorService 接口,您将能够以更优越的方式执行异步任务执行。它管理一个线程池并处理任务的提交和执行。
方法 1:Fork/Join 框架
算法
定义一个表示要执行的任务的 ForkJoinTask 子类。
在子类中实现 compute() 方法,将任务分解成更小的子任务并调用其执行。
组合来自子任务的结果以生成最终结果。
方法 1 的完整可执行代码
示例
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; class MyTask extends RecursiveTask{ private static final int THRESHOLD = 10; private int[] array; private int start; private int end; public MyTask(int[] array, int start, int end) { this.array = array; this.start = start; this.end = end; } @Override protected Integer compute() { if (end - start <= THRESHOLD) { // Perform the computation directly int sum = 0; for (int i = start; i < end; i++) { sum += array[i]; } return sum; } else { // Divide the task into smaller subtasks int mid = start + (end - start) / 2; MyTask leftTask = new MyTask(array, start, mid); MyTask rightTask = new MyTask(array, mid, end); // Fork the subtasks leftTask.fork(); rightTask.fork(); // Combine the results int leftResult = leftTask.join(); int rightResult = rightTask.join(); // Return the final result return leftResult + rightResult; } } } public class ForkJoinExample { public static void main(String[] args) { int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; MyTask task = new MyTask(array, 0, array.length); // Create a ForkJoinPool and invoke the task ForkJoinPool pool = new ForkJoinPool(); int result = pool.invoke(task); System.out.println("Result: " + result); } }
输出
Result: 55
方法 1 中代码的解释
我们的方法包括创建一个名为 MyTask 的专用类别,它派生自 RecursiveTask<Integer>,以便我们可以运行计算并接收输出。为了实现此目标,我们修改 compute() 方法,以便在任务超过我们的设置限制时将其划分为较小的任务。然后,较小的子任务会被分叉,并且它们的结果会被组合在一起以产生最终结果。
方法 2:ExecutorService
算法
使用 Executors 类创建一个 ExecutorService 实例。
定义一个表示要执行的任务的 Callable 或 Runnable 实现。
将任务提交到 ExecutorService 以执行。
如果需要,获取结果。
方法 2 的完整可执行代码
示例
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class MyTask implements Callable<Integer> {
private int[] array;
private int start;
private int end;
public MyTask(int[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = start; i < end; i++) {
sum += array[i];
}
return sum;
}
}
public class ExecutorServiceExample {
public static void main(String[] args) throws Exception {
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
ExecutorService executorService = Executors.newFixedThreadPool(2);
MyTask task1 = new MyTask(array, 0, 5);
MyTask task2 = new MyTask(array, 5, 10);
Future<Integer> future1 = executorService.submit(task1);
Future<Integer> future2 = executorService.submit(task2);
int result = future1.get() + future2.get();
executorService.shutdown();
System.out.println("Result: " + result);
}
}
输出
Result: 55
方法 2 中代码的解释
在这种方法中,我们使用 Executors 类创建一个 ExecutorService,该类提供了一个具有两个线程的固定线程池。我们定义了一个 MyTask 类,它实现了 Callable
方面 |
Fork/Join 框架 |
ExecutorService |
|---|---|---|
语法 |
class ForkJoinTask<V> extends Object |
interface ExecutorService extends Executor |
设计目的 |
任务的递归分解 |
异步任务执行和线程管理 |
粒度 |
最适合细粒度任务 |
适用于细粒度和粗粒度任务 |
任务依赖性 |
隐式处理递归任务分解 |
需要显式提交任务 |
并行性 |
利用工作窃取算法进行负载均衡 |
管理线程池和任务执行 |
结果收集 |
结果以分层方式合并 |
结果通过 Future 对象获取 |
任务提交 |
任务内的递归分解 |
独立提交任务 |
控制 |
对线程管理的控制有限 |
对线程管理和执行有更大的控制权 |
用例 |
分治算法、递归任务 |
独立任务的并发执行 |
结论
总之,Fork/Join 框架和 ExecutorService 都为 Java 中的并发编程提供了强大的机制。Fork/Join 框架专为任务的递归分解而设计,特别适用于可以分解成子任务的问题。它允许通过利用多个线程并合并其结果来实现高效的并行执行。另一方面,ExecutorService 提供了一种更通用的异步任务执行方法,提供线程管理和对执行环境的控制。它非常适合并发执行独立任务并在需要时获取其结果。通过理解这些框架的差异和特性,开发人员可以根据其特定需求选择最合适的方法,从而创建高效且可扩展的并发 Java 程序。
数据结构
网络
关系型数据库管理系统
操作系统
Java
iOS
HTML
CSS
Android
Python
C 语言编程
C++
C#
MongoDB
MySQL
Javascript
PHP