介绍一下 ForkJoinPool

本文深入探讨了ForkJoinPool的原理与应用,包括其如何解决CPU负载不均衡问题,以及通过RecursiveAction和RecursiveTask实现任务拆分与合并的具体方法。通过示例代码展示了无返回值任务与有返回值任务的执行过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍一下 ForkJoinPool

ForkJoinPool 是 JDK1.7 开始提供的线程池。为了解决 CPU 负载不均衡的问题。如某个较大的任务,被一个线程去执行,而其他线程处于空闲状态。

 

ForkJoinTask 表示一个任务,ForkJoinTask 的子类中有 RecursiveAction 和 RecursiveTask。
RecursiveAction 无返回结果;RecursiveTask 有返回结果。
重写 RecursiveAction 或 RecursiveTask 的 compute(),完成计算或者可以进行任务拆分。

 

调用 ForkJoinTask 的 fork() 的方法,可以让其他空闲的线程执行这个 ForkJoinTask;
调用 ForkJoinTask 的 join() 的方法,将多个小任务的结果进行汇总。

 

无返回值打印任务拆分

package constxiong.interview;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;

/**
 * 测试 ForkJoinPool 线程池的使用
 * @author ConstXiong
 * @date 2019-06-12 12:05:55
 */
public class TestForkJoinPool {

	public static void main(String[] args) throws Exception {
		testNoResultTask();//测试使用 ForkJoinPool 无返回值的任务执行
	}
	
	/**
	 * 测试使用 ForkJoinPool 无返回值的任务执行
	 * @throws Exception
	 */
	public static void testNoResultTask() throws Exception {
		ForkJoinPool pool = new ForkJoinPool();
		pool.submit(new PrintTask(1, 200));
		pool.awaitTermination(2, TimeUnit.SECONDS);
		pool.shutdown();
	}
}
	
/**
 * 无返回值的打印任务
 * @author ConstXiong
 * @date 2019-06-12 12:07:02
 */
class PrintTask extends RecursiveAction {
	
	private static final long serialVersionUID = 1L;
	private static final int THRESHOLD = 49;
	private int start;
	private int end;
	
	public PrintTask(int start, int end) {
		super();
		this.start = start;
		this.end = end;
	}
	

	@Override
	protected void compute() {
		//当结束值比起始值 大于 49 时,按数值区间平均拆分为两个任务;否则直接打印该区间的值
		if (end - start < THRESHOLD) {
			for (int i = start; i <= end; i++) {
				System.out.println(Thread.currentThread().getName() + ", i = " + i);
			}
		} else {
			int middle = (start + end) / 2;
			PrintTask firstTask = new PrintTask(start, middle);
			PrintTask secondTask = new PrintTask(middle + 1, end);
			firstTask.fork();
			secondTask.fork();
		}
	}
	
}

 

有返回值计算任务拆分、结果合并

package constxiong.interview;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;

/**
 * 测试 ForkJoinPool 线程池的使用
 * @author ConstXiong
 * @date 2019-06-12 12:05:55
 */
public class TestForkJoinPool {

	public static void main(String[] args) throws Exception {
		testHasResultTask();//测试使用 ForkJoinPool 有返回值的任务执行,对结果进行合并。计算 1 到 200 的累加和
	}
	
	/**
	 * 测试使用 ForkJoinPool 有返回值的任务执行,对结果进行合并。计算 1 到 200 的累加和
	 * @throws Exception
	 */
	public static void testHasResultTask() throws Exception {
		int result1 = 0;
		for (int i = 1; i <= 200; i++) {
			result1 += i;
		}
		System.out.println("循环计算 1-200 累加值:" + result1);
		
		ForkJoinPool pool = new ForkJoinPool();
		ForkJoinTask<Integer> task = pool.submit(new CalculateTask(1, 200));
		int result2 = task.get();
		System.out.println("并行计算 1-200 累加值:" + result2);
		pool.awaitTermination(2, TimeUnit.SECONDS);
		pool.shutdown();
	}
	
}

/**
 * 有返回值的计算任务
 * @author ConstXiong
 * @date 2019-06-12 12:07:25
 */
class CalculateTask extends RecursiveTask<Integer> {

	private static final long serialVersionUID = 1L;
	private static final int THRESHOLD = 49;
	private int start;
	private int end;
	
	public CalculateTask(int start, int end) {
		super();
		this.start = start;
		this.end = end;
	}

	@Override
	protected Integer compute() {
		//当结束值比起始值 大于 49 时,按数值区间平均拆分为两个任务,进行两个任务的累加值汇总;否则直接计算累加值
		if (end - start <= THRESHOLD) {
			int result = 0;
			for (int i = start; i <= end; i++) {
				result += i;
			}
			return result;
		} else {
			int middle = (start + end) / 2;
			CalculateTask firstTask = new CalculateTask(start, middle);
			CalculateTask secondTask = new CalculateTask(middle + 1, end);
			firstTask.fork();
			secondTask.fork();
			return firstTask.join() + secondTask.join();
		}
	}
	
}

 


【Java面试题与答案】整理推荐

 

### ForkJoinPool 线程池概述 ForkJoinPool 是一种特殊的线程池,旨在支持分治算法的并行化操作。这种线程池特别适用于可以分解成多个子任务的工作负载,在处理大量细粒度的任务时表现出色[^1]。 #### 创建与初始化 创建 `ForkJoinPool` 的实例可以通过多种方式完成: ```java // 使用默认参数创建一个新的 ForkJoinPool 实例 ForkJoinPool customThreadPool = new ForkJoinPool(); // 或者指定并行级别来控制最大工作线程数 int parallelismLevel = Runtime.getRuntime().availableProcessors(); customThreadPool = new ForkJoinPool(parallelismLevel); ``` 对于大多数应用来说,默认情况下会自动利用公共的共享线程池 `ForkJoinPool.commonPool()` 来运行异步任务,除非有特殊需求才需自定义配置新实例[^2]。 #### 主要组件介绍 该框架主要包括以下几个核心部分: - **ForkJoinPool**: 负责管理一组工作线程,并调度它们执行提交给它的任务。 - **ForkJoinTask<T>**: 表示可被分割成更小子任务的大任务抽象类;它有两个重要子类 RecursiveAction 和 RecursiveTask,分别对应无返回值和带返回值的情况。 - **ForkJoinWorkerThread**: 执行由 ForkJoinPool 提交的具体任务的实际工作者线程[^3]. #### 关键机制解析 ##### 工作窃取 (Work Stealing) 这是使 ForkJoinPool 效率高的一个重要特性之一。当某个线程完成了自己的所有分配到的任务之后,它可以去其他忙碌中的线程那里“偷走”一部分未完成的任务来进行处理,从而提高了整体资源利用率和吞吐量。 ##### 任务拆解与合并 为了充分利用多核处理器的能力,大任务会被递归地划分为越来越小的部分直到达到一定阈值为止,这些较小单位可以直接被执行而不再进一步细分。一旦各个分支都已完成计算,则通过逆向遍历树形结构逐步汇总结果。 #### 应用场景举例 最常见的应用场景是在 Stream API 中调用了 `parallelStream()` 方法后的内部实现上采用了此线程池作为后台支撑。另外,“虚拟线程”的概念也依赖于此类线程池得以高效运作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值