ForkJoin框架是Java 7引入的一部分,位于java.util.concurrent包中。它主要用于并行处理任务,特别是递归任务。ForkJoin框架的核心思想是将大任务分成多个小任务,分别执行,然后将结果合并。它非常适合处理可以递归分解的任务。
以下是ForkJoin框架的主要应用和典型示例:
1. 并行计算
计算数组的和
ForkJoin框架可以用于并行计算数组的和,将数组分成多个子数组,每个子数组分别计算其和,然后合并结果。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
public class ForkJoinSum extends RecursiveTask<Long> {
private static final int THRESHOLD = 100; // 阈值,决定任务是否需要拆分
private List<Integer> numList;
private int start;
private int end;
public ForkJoinSum(List<Integer> numList, int start, int end) {
this.numList = numList;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
// 任务足够小,直接计算
long sum = 0;
for (int i = start; i < end; i++) {
sum += numList.get(i);
}
return sum;
} else {
// 任务太大,拆分为两个子任务
int mid = (start + end) >> 1;
ForkJoinSum leftTask = new ForkJoinSum(numList, start, mid);
ForkJoinSum rightTask = new ForkJoinSum(numList, mid, end);
// 执行子任务
leftTask.fork();
rightTask.fork();
// 合并结果
long leftResult = leftTask.join();
long rightResult = rightTask.join();
return leftResult + rightResult;
}
}
public static void main(String[] args) {
long N = 10000;
List<Integer> list = new ArrayList<>();
for (int i = 1; i <= N; i++) {
list.add(i);
}
//ForkJoin
ForkJoinPool pool = new ForkJoinPool();
ForkJoinSum task = new ForkJoinSum(list, 0, list.size());
long result = pool.invoke(task);
System.out.println("Sum: " + result); //50005000
}
}
2. 并行处理大数据集
快速排序
使用ForkJoin框架实现快速排序,可以将排序任务递归地分解为子任务,并行处理每个子任务,从而加快排序速度。
import java.util.Arrays;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;
public class ForkJoinQuickSort extends RecursiveAction {
private static final int THRESHOLD = 1000; // 阈值,决定任务是否需要拆分
private int[] arr;
private int start;
private int end;
public ForkJoinQuickSort(int[] arr, int start, int end) {
this.arr = arr;
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if (end - start <= THRESHOLD) {
quickSort(arr, start, end);
} else {
int pivot = partition(arr, start, end);
ForkJoinQuickSort leftTask = new ForkJoinQuickSort(arr, start, pivot - 1);
ForkJoinQuickSort rightTask = new ForkJoinQuickSort(arr, pivot + 1, end);
invokeAll(leftTask, rightTask);
}
}
private void quickSort(int[] arr, int start, int end) {
if (start < end) {
int pivot = partition(arr, start, end);
quickSort(arr, start, pivot - 1);
quickSort(arr, pivot + 1, end);
}
}
private int partition(int[] arr, int start, int end) {
int pivot = arr[end];
int i = start - 1;
for (int j = start; j < end; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, end);
return i + 1;
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = new int[10000];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 10000);
}
ForkJoinPool pool = new ForkJoinPool();
ForkJoinQuickSort task = new ForkJoinQuickSort(arr, 0, arr.length - 1);
pool.invoke(task);
// 验证排序结果
boolean sorted = true;
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
sorted = false;
break;
}
}
System.out.println("Sorted: " + sorted);
System.out.println(Arrays.toString(arr));
//Sorted: true
//[0, 1, 3, 4, 6....... 9996, 9997, 9998, 9998, 9999]
}
}
3. 并行图像处理
图像滤镜应用
使用ForkJoin框架并行处理图像滤镜应用,可以显著提高处理速度,特别是对于大图像。
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;
public class ForkJoinImageFilter extends RecursiveAction {
private static final int THRESHOLD = 10000;
private BufferedImage image;
private int start;
private int end;
public ForkJoinImageFilter(BufferedImage image, int start, int end) {
this.image = image;
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if (end - start <= THRESHOLD) {
for (int i = start; i < end; i++) {
int rgb = image.getRGB(i % image.getWidth(), i / image.getWidth());
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
int gray = (red + green + blue) / 3;
int newRgb = (gray << 16) | (gray << 8) | gray;
image.setRGB(i % image.getWidth(), i / image.getWidth(), newRgb);
}
} else {
int mid = (start + end) / 2;
ForkJoinImageFilter leftTask = new ForkJoinImageFilter(image, start, mid);
ForkJoinImageFilter rightTask = new ForkJoinImageFilter(image, mid, end);
invokeAll(leftTask, rightTask);
}
}
public static void main(String[] args) throws Exception {
BufferedImage image = ImageIO.read(new File("input.jpg"));
ForkJoinPool pool = new ForkJoinPool();
ForkJoinImageFilter task = new ForkJoinImageFilter(image, 0, image.getWidth() * image.getHeight());
pool.invoke(task);
ImageIO.write(image, "jpg", new File("output.jpg"));
}
}
- 递归算法
斐波那契数列
使用ForkJoin框架计算斐波那契数列,可以并行计算每个子问题。
package test;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
public class ForkJoinFibonacci extends RecursiveTask<Long> {
private static final int THRESHOLD = 10;
private int n;
public ForkJoinFibonacci(int n) {
this.n = n;
}
@Override
protected Long compute() {
if (n <= THRESHOLD) {
return fibonacci(n);
} else {
ForkJoinFibonacci task1 = new ForkJoinFibonacci(n - 1);
ForkJoinFibonacci task2 = new ForkJoinFibonacci(n - 2);
task1.fork();
long result2 = task2.compute();
long result1 = task1.join();
return result1 + result2;
}
}
private long fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
public static void main(String[] args) {
int n = 40;
ForkJoinPool pool = new ForkJoinPool();
ForkJoinFibonacci task = new ForkJoinFibonacci(n);
long result = pool.invoke(task);
System.out.println("Fibonacci number " + n + " is " + result);
}
}
总结
ForkJoin框架适用于需要递归分解的并行任务,如数组求和、快速排序、图像处理、斐波那契数列等。通过将大任务分解为更小的子任务并行执行,可以充分利用多核处理器,提高计算效率。