JAVA并行计算之ForkJoinTask使用样例

ForkJoinTask这个名字,第一次听到,立马让我想起了hadoop里的mapreduce编程模型。

处理数据时主要分为两个阶段:1.map(Fork)阶段,单程序(线程)处理计算阶段  2.reduce(join)阶段,计算结果汇总阶段

处于好奇,我还是决定自己来写一个简单的ForkJoinTask的例子,体验下

例子的功能描述:

计算1+2+3+……1000000000的和,即1000000000!的结果


先写一个不采用ForkJoinTask的实现方式,以此做对比

/**
 * desc:计算1+2+3+……1000000000的和
 * author: haiyangp
 * date:   2017/8/25
 */
public class NotForkJoinTask {

    public static void main(String[] args) {
        new Thread(()->{
            Long sum = 0l;
            Long maxSize = 1000000000l;
            long startTime = System.currentTimeMillis();
            for (Long i = 1l; i <= maxSize; i++) {
                sum += i;
            }
            System.out.println("结果--》result:"+sum);
            long endTime = System.currentTimeMillis();
            System.out.println("costTime:"+(endTime-startTime));
        }).start();

    }
}

运行结果为:

结果--》result:500000000500000000
costTime:10121


采用ForkJoinTask的代码为:

/**
 * desc: 计算task(计算1+2+3+……1000000000的和)
 * author: haiyangp
 * date:   2017/8/25
 */
public class CountTask extends RecursiveTask<Long> {
    Long maxCountRange = 100000000l;//最大计算范围
    Long startNum, endNum;

    public CountTask(Long startNum, Long endNum) {
        this.startNum = startNum;
        this.endNum = endNum;
    }

    @Override
    protected Long compute() {
        long range = endNum - startNum;
        long sum = 0;
        if (range >= maxCountRange) {//如果这次计算的范围大于了计算时规定的最大范围,则进行拆分
            //每次拆分时,都拆分成原来任务范围的一半
            //如1-10,则拆分为1-5,6-10
            Long middle = (startNum + endNum) / 2;
            CountTask subTask1 = new CountTask(startNum, middle);
            CountTask subTask2 = new CountTask(middle + 1, endNum);
            //拆分后,执行fork
            subTask1.fork();
            subTask2.fork();

            sum += subTask2.join();
            sum += subTask1.join();
        } else {//在范围内,则进行计算
            for (; startNum <= endNum; startNum++) {
                sum += startNum;
            }
        }
        return sum;
    }

    public static void main(String[] args) {
        Long startNum = 1l;
        Long endNum = 1000000000l;

        long startTime = System.currentTimeMillis();

        CountTask countTask = new CountTask(startNum, endNum);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        Future<Long> result = forkJoinPool.submit(countTask);
        try {
            System.out.println("结果--》result:" + result.get());
            long endTime = System.currentTimeMillis();
            System.out.println("costTime:" + (endTime - startTime));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

运行结果为:

结果--》result:500000000500000000
costTime:4081


从结果分析来看,在此程序中,单线程耗时10121毫秒而采用多线程拆分后耗时为4081,通过ForkJoinTask进行分而治之的程序比单线程处理的程序耗费的时间相差差不多为一倍,进而说明了ForkJoinTask还是不错的,多线程跑得确实比单线程的快

对于为什么ForkJoinTask比单线程的快呢?我看了一些文章后,才知道原来是主要因为ForkJoinPool这个线程池下有一个双端队列,以及线程获取任务时采用的Work Stealing模式来获取的。

在ForkJoinPool的源码中我们也能看到相应的代码与说明:

/**
 * Queues supporting work-stealing as well as external task
 * submission. See above for descriptions and algorithms.
 * Performance on most platforms is very sensitive to placement of
 * instances of both WorkQueues and their arrays -- we absolutely
 * do not want multiple WorkQueue instances or multiple queue
 * arrays sharing cache lines. The @Contended annotation alerts
 * JVMs to try to keep instances apart.
 */
@sun.misc.Contended
static final class WorkQueue {

Queues supporting work-stealing as well as external task submission.(队列支持工作窃取以及外部的任务提交)

对于ForkJoinTask更多的说明,在https://yq.aliyun.com/articles/48739这个链接下的3篇文章中有较为详细的说明


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是Java使用CompletableFuture并行计算任务的示例: ```java import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class CompletableFutureExample { public static void main(String[] args) throws ExecutionException, InterruptedException { CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> { System.out.println("Task 1 started"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task 1 completed"); return 100; }); CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> { System.out.println("Task 2 started"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task 2 completed"); return 200; }); CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> { System.out.println("Task 3 started"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task 3 completed"); return 300; }); CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3); allFutures.get(); System.out.println("Result 1: " + future1.get()); System.out.println("Result 2: " + future2.get()); System.out.println("Result 3: " + future3.get()); } } ``` 在这个示例中,我们创建了三个CompletableFuture对象,每个对象都代表一个任务。我们使用supplyAsync()方法来异步执行每个任务。然后,我们使用allOf()方法将所有CompletableFuture对象组合在一起,以便在所有任务完成后获取结果。最后,我们使用get()方法获取每个任务的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水中加点糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值