Java 是一种目前比较流行的后端编程语言,因为其强大的并发性能,使其成为开发多线程应用程序的绝佳选择。Java 中简化并发管理和执行任务过程的两个关键组件是 ExecutorService 和 Fork/Join 框架。在本文中,我们将探讨这两个框架,并以简单易懂的方式对它们进行讲解。
ExecutorService
ExecutorService 就像一组工作者(线程)的管理器,可以帮助你以受控的方式并发执行任务。它抽象化了管理线程的大部分复杂性。让我们举一个简单的例子来说明它的用法。
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorServiceExample {
public static void main(String[] args) {
// Create an ExecutorService with a fixed pool of 4 threads
ExecutorService executorService = Executors.newFixedThreadPool(4);
// Submit tasks for execution
for (int i = 0; i < 10; i++) {
final int taskNumber = i;
executorService.execute(() -> {
System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
});
}
// Shutdown the ExecutorService when done
executorService.shutdown();
}
}
在这个例子中,我们:
1.ExecutorService使用 . 创建一个具有 4 个线程的固定池Executors.newFixedThreadPool(4)。
- 使用 Executors.newFixedThreadPool(4) 创建一个具有固定 4 个线程池的 ExecutorService。
- 使用 execute 方法提交 10 个任务供执行。
- ExecutorService 负责管理这些任务的线程分配和重用。
- 执行完毕后,我们将关闭 ExecutorService。
Fork/Join Framework

Fork/Join Framework 是一种更专业的并行处理工具。它非常适合需要将大型任务划分为较小的子任务,然后合并其结果的情况。让我们通过一个经典的例子来了解它--计算数组中元素的总和。
java
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
public class ForkJoinExample {
public static void main(String[] args) {
int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
ForkJoinPool pool = new ForkJoinPool();
int result = pool.invoke(new SumTask(data, 0, data.length));
System.out.println("Sum: " + result);
}
}
class SumTask extends RecursiveTask<Integer> {
private int[] data;
private int start;
private int end;
public SumTask(int[] data, int start, int end) {
this.data = data;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
if (end - start <= 3) { // Small enough, do the task directly
int sum = 0;
for (int i = start; i < end; i++) {
sum += data[i];
}
return sum;
} else {
int mid = start + (end - start) / 2;
SumTask leftTask = new SumTask(data, start, mid);
SumTask rightTask = new SumTask(data, mid, end);
leftTask.fork(); // Fork new tasks
int rightResult = rightTask.compute(); // Compute one part
int leftResult = leftTask.join(); // Wait for the other part
return leftResult + rightResult;
}
}
}
在这个例子中,我们:
- 初始化数据数组。
- 创建 ForkJoinPool,这是 Fork/Join 框架的核心。
- 定义一个扩展 RecursiveTask 的 SumTask 类。我们在这里指定要执行的任务。
- SumTask 类将数组求和的任务分解为更小的子任务,并将结果合并。框架会为我们处理任务分配和结果汇总。
Fork/Join 框架如何工作
Fork/Join 框架采用分而治之的策略来实现任务并行化。以下是其工作原理的逐步分解:
- 主任务(本例中为 SumTask)需要解决一个求和问题。它会检查求和的大小是否小到足以直接求解(在本例中,当start和end之间的差值小于或等于 3 时)。
- 如果数值很小,它就会直接计算出结果。在本例中,它会对数组中 start 和 end 之间的元素求和。
- 如果数值太大,主任务会将其拆分为两个子任务,即 leftTask 和 rightTask,以计算求和中较小的部分。
- 然后左任务会被分叉,这意味着它将被提交给并行执行。这样,框架就能为每个子任务分配单独的线程。
- 在直接计算右任务的同时,允许左任务并行执行。
- 一旦两个子任务都完成,左任务和右任务的结果就会合并在一起,从而有效地合并子任务结果,得到最终结果。 这种分而治之的方法会递归地继续下去,直到所有子任务都小到足以直接计算,并将它们的结果组合起来产生总体结果。
结论
ExecutorService 和 Fork/Join 框架使 Java 中的并发变得更简单、更高效。ExecutorService 管理线程,使并发执行任务变得更容易,而 Fork/Join Framework 专为并行处理而设计,允许您划分和征服复杂的任务。
这些工具是 Java 开发人员工具箱的宝贵补充,可以有效利用多个内核并提高应用程序性能。通过掌握这些框架,您可以轻松构建高性能、多线程的 Java 应用程序。