Future&ForkJoin框架原理
Future:
Future是一种异步计算机制,可以在一个线程中提交一个任务,并在另一线程中的某个时候获取该任务的结果。Future提供了一个get方法,该方法会阻塞调用线程直到计算结果可用。Future还提供了isDone方法,用于检查计算是否已经完成。
示例代码:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
// 模拟长时间计算
Thread.sleep(3000);
return 100;
});
System.out.println("等待计算结果...");
while (!future.isDone()) {
// 等待计算结果
}
System.out.println("计算结果为:" + future.get());
executor.shutdown();
在上面的示例中,我们创建了一个ExecutorService,然后提交了一个Callable任务,该任务会休眠3秒钟,然后返回整数100。我们使用Future的get方法等待任务完成并获取结果。可以看到,在等待任务完成时,调用线程会一直被阻塞。
ForkJoin框架:
ForkJoin框架是一种并行计算框架,自JDK1.7引入以来,已经成为Java并发编程中的重要组成部分。ForkJoin框架通过将大任务拆分为小任务,然后在不同的线程中并行执行这些小任务,最终将所有的小任务结果合并得到最终结果。
ForkJoin框架中有两个重要的类:ForkJoinPool和ForkJoinTask。ForkJoinPool是一个特殊的线程池,用于执行ForkJoinTask。ForkJoinTask表示可以被拆分为更小任务的任务。ForkJoinTask有两种类型:RecursiveTask和RecursiveAction。RecursiveTask表示有返回值的任务,而RecursiveAction表示没有返回值的任务。
示例代码:
class SumTask extends RecursiveTask<Long> {
private static final int THRESHOLD = 10000;
private final int[] array;
private final int start;
private final int end;
SumTask(int[] array, int start, int end) {
this.array = array;
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 += array[i];
}
return sum;
} else {
int middle = (start + end) >>> 1;
SumTask leftTask = new SumTask(array, start, middle);
SumTask rightTask = new SumTask(array, middle, end);
leftTask.fork();
rightTask.fork();
return leftTask.join() + rightTask.join();
}
}
}
public static void main(String[] args) {
int[] array = new int[100000];
for (int i = 0; i < array.length; i++) {
array[i] = i + 1;
}
ForkJoinPool pool = new ForkJoinPool();
long startTime = System.currentTimeMillis();
long result = pool.invoke(new SumTask(array, 0, array.length));
long endTime = System.currentTimeMillis();
System.out.println("计算结果为:" + result);
System.out.println("耗时:" + (endTime - startTime) + "毫秒");
pool.shutdown();
}
在上面的示例中,我们创建了一个有10万个元素的整数数组,然后创建了一个SumTask,该任务用于计算数组中所有元素的和。如果数组的长度小于等于阈值10000,我们直接计算结果并返回;否则,我们将数组拆分为两个子数组,分别创建任务计算子数组的和,并使用fork方法将任务提交到ForkJoinPool中。最后,我们使用join方法获取子任务的计算结果,并将结果进行合并。可以看到,在ForkJoin框架中,我们使用更少的代码实现了并行计算,同时也减少了很多线程同步的开销。
小故事
有一个农夫需要在他的田地里种植许多植物。为了尽快完成这项任务,他决定雇佣一些工人帮他。他将他的田地划分成许多小块,并为每个工人分配了一个小块来种植。每个工人都可以在他们的小块周围挖掘土壤,种下植物,并且记录他们的进度。
Future框架就像雇佣工人一样,它将任务划分成小部分并分配给不同的线程来处理。在我们的故事中,每个工人都在记录自己的进度,这就是Future的关键:每个线程都可以记录自己的进度并返回自己的结果给主线程。
那么,ForkJoin框架又是什么呢?它就像一个老板,会监督所有的工作并确定每个线程的进度。在我们的故事中,老板在收集工人的报告时会确定哪个区域已经完成,哪些工人需要帮助他们完成他们的任务。ForkJoin框架也是这样,它会监督所有任务的执行并决定是否需要fork新的任务,并将它们分配给其他线程来处理。
总的来说,Future和ForkJoin框架结合起来可以将大型任务分成小的部分,并同时利用多个线程来处理任务,从而提高系统的效率和响应速度。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?