【Future&ForkJoin框架原理】

文章目录

    • Future&ForkJoin框架原理
    • 小故事

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框架结合起来可以将大型任务分成小的部分,并同时利用多个线程来处理任务,从而提高系统的效率和响应速度。

你可能感兴趣的:(#,并发编程,java,jvm,开发语言)