ForkJoin 线程池[通俗易懂]

ForkJoin 线程池[通俗易懂]一、分而治之严格来讲,分而治之不算一种模式,而是一种思想。它可以将一个大任务拆解为若干个小任务并行执行,提高系统吞吐量。主要讲两个场景,Master-Worker模式,ForkJoin线程池。ForkJoin线程池是jdk7之后引入的一个并行执行任务的框架,其核心思想也是将任务分割为子任务,有可能子任务还是很大,还需要进一步拆解,最终得到足够小的任务。将分割出来的子任务放入双端队列中,然后几个启动线程从双端队列中获取任务执行。子任务执行的结果放到一个队列里,另起线程从队列中获取数据,合并结果。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、分而治之

严格来讲,分而治之不算一种模式,而是一种思想。它可以将一个大任务拆解为若干个小任务并行执行,提高系统吞吐量。主要讲两个场景,Master-Worker 模式,ForkJoin 线程池。

ForkJoin 线程池是Jdk7之后引入的一个并行执行任务的框架。其核心思想是将任务分割为子任务,有可能子任务还是很大,还需要进一步拆解,最终得到足够小的任务。将分割出来的子任务放入双端队列中,然后几个启动线程从双端队列中获取任务执行。子任务执行的结果放到一个队列里,另起线程从队列中获取数据,合并结果。ForkJoin 线程池[通俗易懂]

二、ForkJoin 与传统线程池的区别

采用 “工作窃取”模式(work-stealing):当执行新的任务时,它可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。 相较于一般的线程池,ForkJoin 的优势体现在对其中包含的任务的处理方式上。在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。而 ForkJoin,如果某个子问题由于等待另外一个子问题的完成而无法继续运行,那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行。这种方式减少了线程的等待时间,提高了性能。

三、案例

计算从 0 到 100L 的累加求和。CountTask 继承自 RecursiveTask,可以携带返回值。每次分解大任务,简单的将任务划分为 10 个等规模的小任务,并使用 fork() 提交子任务。在子任务中通过 THRESHOLD(门槛) 设置子任务分解的阈值,如果当前需要求和的总数大于 THRESHOLD,则子任务需要再次分解,如果子任务可以直接执行,则进行求和操作,返回结果。最终等待所有的子任务执行完毕,对所有结果求和。

public class CountTask extends RecursiveTask<Long> { 
   
    //任务分解的阈值
    private static final int THRESHOLD = 11;
    private long start;
    private long end;

    public CountTask(long start, long end) { 
   
        this.start = start;
        this.end = end;
    }

    public Long compute() { 
   
        long sum = 0;
        boolean canCompute = (end - start) < THRESHOLD;
        if (canCompute) { 
   
            for (long i = start; i <= end; i++) { 
   
                sum += i;
            }
        } else { 
   
            //分成100个小任务
            long step = (start + end) / 10;
            ArrayList<CountTask> subTasks = new ArrayList<CountTask>();
            long pos = start;
            for (int i = 0; i < 10; i++) { 
   
                long lastOne = pos + step;
                if (lastOne > end) { 
   
                    lastOne = end;
                }
                CountTask subTask = new CountTask(pos, lastOne);
                pos += step + 1;
                //将子任务推向线程池
                subTasks.add(subTask);
                subTask.fork();
            }

            for (CountTask task : subTasks) { 
   
                //对结果进行join
                sum += task.join();
            }
        }
        return sum;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException { 
   
        ForkJoinPool pool = new ForkJoinPool();
        // 累加求和 0 -> 100L
        CountTask task = new CountTask(0, 100L);
        ForkJoinTask<Long> result = pool.submit(task);
        System.out.println("sum result : " + result.get());
    }
}

ForkJoin 线程池使用一个无锁的栈来管理空闲线程,如果一个工作线程暂时取不到可用的任务,则可能被挂起。挂起的线程将被压入由线程池维护的栈中,待将来有任务可用时,再从栈中唤醒这些线程。Java8 的并行流就是基于 ForkJoin,并进行了优化

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/191575.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 搜集对编程有帮助的论坛以及个人空间信息_猿编程怎么样

    搜集对编程有帮助的论坛以及个人空间信息_猿编程怎么样(持续更新中)论坛:编程论坛——中国最大的编程者社区:http://bbs.bc-cn.net/编程论坛-编程爱好者学习的净土,程序员交流的园地:http://www.programbbs.com/豆瓣小组:java小组http://www.douban.com/group/java/大富翁论坛:http://w

    2022年9月1日
    3
  • linux下mysql命令

    linux下mysql命令1.linux下启动mysql的命令:mysqladminstart/ect/init.d/mysqlstart(前面为mysql的安装路径)2.linux下重启mysql的命令:mys

    2022年7月2日
    25
  • leetcode-91解码方法(动态规划|记忆化搜索)[通俗易懂]

    leetcode-91解码方法(动态规划|记忆化搜索)[通俗易懂]一条包含字母 A-Z 的消息通过以下映射进行了 编码 :‘A’ -> 1‘B’ -> 2…‘Z’ -> 26要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,“111” 可以将 “1” 中的每个 “1” 映射为 “A” ,从而得到 “AAA” ,或者可以将 “11” 和 “1”(分别为 “K” 和 “A” )映射为 “KA” 。注意,“06” 不能映射为 “F” ,因为 “6” 和 “06” 不同。给你一个只含数字的 非空 字符串

    2022年8月8日
    4
  • Mysql 导出数据到Excel

    Mysql 导出数据到Excel

    2021年8月7日
    67
  • 在oracle中恢复删除的表 FLASHBACK TABLE

    在oracle中恢复删除的表 FLASHBACK TABLE

    2021年6月17日
    89
  • tar 打包隐藏文件[通俗易懂]

    tar 打包隐藏文件[通俗易懂]前言:先说一下遇到的场景:前段时间在配合做DevOps,组内有块代码是php的,需要用tar命令打包归档上传到nexus库,后来发现解压出来的包居然缺失了隐藏文件(配置文件),查了一下资料解决了,这里记录一下。1.tar命令常规用法-c 创建新的档案文件-C 指定到要解压到的目录。注意:该目录必须存在-f 指定打包的文件名。在f之后要立即接打包文件名!不能再加参数!-x 解压-O 将文件解压到标准输出-p 使用原文件的原来属性-P 创建归档文件,使用绝对路径-t 列出档

    2022年5月31日
    62

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号