JAVA多线程进阶篇 12、JUC线程池之ForkJoinPool

Java中的ForkJoinPool使用详解(带案例) ForkJoinPool 是 Java 7 引入的一个线程池实现,位于 java.util.concurrent 包下,专为分治算法(Divide-and-Conquer)设计,特别适合处理可分解为多个子任务的复杂任务。它的核心思想是将大任务 "拆分"(fork)为小任务,并行执行后再 "合并"(join)结果,同时通过工作窃取(Work Stealing)机制提高线程利用率。 阅读详情

1. 为什么要使用线程池?

如果放任线程无限制地创建,会耗尽CPU资源,并且降低系统的响应速度。
为了更好的对线程进行管理,实现线程的统一分配,调优和监控,降低资源消耗。
JUC设计了线程池。线程池从机制上分为两种.,一是ThreadPoolExecutor,另一类是ForkJoinPool。

  • ThreadPoolExecutor
    使用多个线程和阻塞队列实现对线程和任务进行管理的工具。
  • ForkJoinPool
    将一个大任务拆分为很多小任务来异步执行的管理的工具。

1.1 Executor 和 ExecutorService

ThreadPoolExecutor 和 ForkJoinPool 都实现了Executor 和 ExecutorService接口。
Executor 和 ExecutorService接口规定了对线程池使用的提交任务和关闭任务的方法。

1.2 线程池提交任务

  • execute()方法是Executor接口规定的。只能接受Runnable类型的任务。
    void execute(Runnable command);
  • submit()方法是ExecutorService接口规定的。有返回值,且可以通过Future.get()抛出Exception
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);

1.3 线程池关闭

  • shutdown()方法,shutdown只是将线程池的状态设置为SHUTWDOWN状态,正在执行的任务会继续执行下去,没有被执行的则中断。

  • shutdownNow(),而shutdownNow则是将线程池的状态设置为STOP,正在执行的任务则被停止,没被执行任务的则返回。

    shutdownNow会停止正在运行的线程。

2. ForkJoinPool

2.1 ForkJoinPool原理

ForkJoinPool使用分治算法(Divide-and-Conquer)把任务递归的拆分为各个子任务,,尽可能的使用所有可用的计算能力来提升应用性能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pIbUykHP-1647316188651)(https://s2.loli.net/2022/03/15/YMZaRk17vzgGxVJ.png)]

2.2 ForkJoinTask

ForkJoinPool 只接收 ForkJoinTask 任务。我们一般都会继承 RecursiveTask 、RecursiveAction 或 CountedCompleter 来实现我们的业务需求,而不会直接继承 ForkJoinTask 类。

  • RecursiveTask 是 ForkJoinTask 的子类,是一个可以递归执行的 ForkJoinTask。
  • RecursiveAction 是一个无返回值的 RecursiveTask。
  • CountedCompleter 在任务完成执行后会触发执行一个自定义的钩子函数。

2.3 继承实现一个RecursiveTask

继承RecursiveTask 需要 重写其compute()方法,该方法的返回值是泛型。

当任务较大的时候 就将任务切分,当任务规模能够直接处理就在本地处理,并返回结果。

RecursiveTask2类,是自定义的实现简单的数字累加。当计算规模在100个数以内,就直接使用循环计算。如果大于100个数,将划分为两个部分,并创建两个RecursiveTask2对象fork()后再join()。

public class RecursiveTask2 extends RecursiveTask<Integer> {

    int start,end;
    static final int MAXNUM=100;

    public RecursiveTask2(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if(end-start>MAXNUM) {
            int mid = start+(end-start)/2;
            RecursiveTask2 task1 = new RecursiveTask2(start,mid);
            RecursiveTask2 task2 = new RecursiveTask2(mid,end);
            task1.fork();
            task2.fork();
            return task1.join()+task2.join();
        }
        else {
            int sum = 0;
            while (start<end) {
                start++;
                sum+=start;
            }
            return sum;
        }
    }
}

2.4 使用ForkJoinPool计算RecursiveTask任务

将自定义的任务提交到ForkJoinPool。ForkJoinPool将不断创建子线程任务,直到每个线程能计算的任务规模在预定的规模下,然后再汇总计算结果。

public class ForkJoinPoolTest2 {
    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        RecursiveTask2 recursiveTask2 = new RecursiveTask2(0, 1000);
        forkJoinPool.execute(recursiveTask2);
        System.out.println(recursiveTask2.join());
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

500500

2.5 WorkStealingPool

Executors工具类也提供了创建ForkJoinPool的方法。源码如下:

 public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

WorkStealingPool是一类比较特殊的ForkJoinPool。每个线程分到自己的任务后,如果发现自己的任务已完成那么它可以“窃取”其他线程未完成的任务。进一步提升了效率和使用率。其原理如下

  • 每个线程都有自己的一个WorkQueue,该工作队列是一个双端队列。划分的子任务调用fork时,都会被push到自己的队列中。

  • 所有者线程调用pop方法,从WorkQueue提取任务。

  • 当线程完成了任务,自己所属的WorkQueue为空。则随机从另一个线程的队列末尾调用poll方法窃取任务。

public class ForkJoinPoolTest3 {
    public static void main(String[] args) {
        ExecutorService forkJoinPool = Executors.newWorkStealingPool(20);
        for(int i=0;i<100;i++) {
            forkJoinPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        forkJoinPool.shutdown();;
    }
}

总结

ForkJoinPool使用分治算法(Divide-and-Conquer)把任务递归的拆分为各个子任务,,尽可能的使用所有可用的计算能力来提升应用性能。

多线程系列在github上有一个开源项目,主要是本系列博客的实验代码。

https://github.com/forestnlp/concurrentlab

如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。

您的支持是对我最大的鼓励。

java多线程——juc总结 1.主要内容1. Java JUC 简介2. volatile 关键字-内存可见性3. 原子变量-CAS算法4. ConcurrentHashMap 锁分段机制5. CountDownLatch 闭锁6. 实现 Callable 接口7. Lock 同步锁8. Condition 控制线程通信9. 线程按序交替10. ReadWriteLock 读写锁11. 线程八锁12. 线程池13. 线程调度... 阅读详情

相关推荐

java juc包介绍

目录 1.Java JUC 简介 2.volatile 关键字-内存可见性 3.原子变量-CAS算法 4.ConcurrentHashMap 锁分段机制 5.CountDownLatch 闭锁 6.实现Callable 接口 7.Lock 同步锁 8.Condition 控制线程通信 9.线程按序交替 10.ReadWriteLock 读写锁 11.线程八锁 12.线程池 13.线程调度 14.F...

ganyongming的博客 1137

Java-ForkJoinPool详解

今天和大家分享JDK1.7中出现的ForkJoinPool类。我们将从三个维度介绍ForkJoinPool。首先介绍ForkJoinPool出现的背景与思想,其次介绍ForkJoinPool使用方法以及性能比较,最后通过手写一个ForkJoinPool来展示其原理。

shadow_zed的博客 1万+

一文秒懂 Java ForkJoinPool

因为,即使是使用一个简单的 ThreadPoolExecutor ,也会在不断的递归中快速耗尽线程。在 fork/join 框架中,任何任务都可以生成 ( fork ) 多个子任务并使用 join() 方法等待它们的完成。fork/join 框架的好处是它不会为每个任务或子任务创建新线程,而是实现了 工作窃取 (每个任务都接收自己的节点,并将其值添加到其子节点的值之和上。关于 fork/join 框架的详细信息,你可以访问我们的 一文秒懂 Java Fork/Join。接下来,我们看一个使用。

jysf98746的博客 190

Java-ForkJoinPool(线程池-工作窃取算法)

Fork 就是把一个大任务切分为若干个子任务并行地执行,Join 就是合并这些子任务的执行结果,最后得到这个大任务的结果。Fork/Join 框架使用的是工作窃取算法。

weixin_45203607的博客 3108

Java 线程池 ForkJoinPool(一)

线程管理器(ThreadPool):用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务。工作线程(PoolWorker):线程池中的线程,在没有任务时处于等待状态,可以循环的执行任务;任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它注意规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;任务队列(taskQueue):用于存放没有处理的任务,提供一种缓冲机制。

gmHappy 1256

【Java多线程】JUC之线程池(四)ForkJoin

Fork/Join框架是`Java7`提供的一个用于`并行执行任务`的框架,可以把`大任务分割成若干个小任务`,`最终汇总每个小任务结果后得到大任务结果的框架`。 可以通过Fork和Join这两个单词来理解下Fork/Join框架 - **Fork**就是把一个`大任务` `切分` 为`若干子任务并行的执行` - **Join**就是`合并这些子任务的执行结果`,最后得到这个`大任务的结果`。

墩墩分墩 1225

JUC学习笔记及拓展

JUC学习笔记及拓展Java JUC1 Java JUC简介2 volatile 关键字-内存可见性2.1 内存可见性2.2 volatile 关键字3 原子变量与CAS算法3.1 原子变量3.1.1 i++的原子性问题3.1.2 原子变量3.2 CAS算法3.2.1 ABA问题3.2.2 CAS在JAVA中底层的实现3.3 原子性与可见性区别4 ConcurrentHashMap4.1 锁粒度4.2 锁分段4.3 其它4.4 写入并复制5 CountDownLatch(闭锁)5.1 概念5.2 方法介绍6

yZzc_XQ的博客 3924

从零开始利用MATLAB进行FPGA设计(六)用ADC采集信号教程1

用AN9238采集信号的方法(1),包含PLL、FIFO、ILA的基础教程。

WZT725的博客 3094

Java多线程 JUC之线程池的使用详解及其扩展分析(ThreadPoolExecutor、ForkJoinPool等)

一 前言 谈线程池前有必要回顾一下多线程,

涅 槃——沉默、寡言、静思、实干 478

ESP32 CAM使用教程(入门级)

串口被占用,可以关闭其他使用到串口的界面;先将手机也连上wifi,然后使用手机浏览器打开这个IP地址,注意手机连接的wifi需要和开发板的wifi一致,也就是程序里自己修改的那个wifi,否则无法打开IP地址;将开发板连接到电脑,点击点击工具→端口,然后选择自己实际接的COM口,不清楚COM口的可以打开电脑设备管理器查看一下,插拔设备看看哪个COM口会刷新就是哪个COM口;安装好esp32库之后,点击工具→开发板→esp32→AI Thinker ESP32-CAM,型号要仔细找找,不要选错了;

qq_34426854的博客 2万+

【无标题】ReaxFF拟合参数以及算法安装

ReaxFF拟合参数以及算法安装

zmzyzm的博客 1419

JUC

Java JUC1.Java JUC 简介2.volatile 关键字-内存可见性3.原子变量-CAS算法原子变量4.ConcurrentHashMap 锁分段机制5.CountDownLatch 闭锁6.实现Callable 接口多线程详解7.Lock 同步锁多线程详解8.Condition 控制线程通信 线程按序交替9.ReadWriteLock 读写锁10.线程八锁11.线程池12.线程调度13.ForkJoinPool 分支/合并框架工作窃取 1.Java JUC 简介 在Java 5.0 提供了

zsxfa的博客 151

告别jom Error 2:深入理解QtCreator、CMake与MSVC工具链的协作机制

本文深入解析QtCreator构建过程中常见的jom Error 2问题,揭示CMake与MSVC工具链的协作机制。从CMake生成器的工作原理到MSVC工具链的组件协作,帮助开发者系统化诊断构建错误,提升开发效率。

weixin_30654419的博客 430

JUC完整使用

实战JUC一级目录二级目录三级目录 一级目录 二级目录 三级目录

小坏说Java,一个专注Java微服务架构的实战,Java全栈教程,SpringBoot, SpringCloud微服务到分布式、高并发架构,大数据开发,运维实战,K8S、Docker容器为一体的教程,结合企业级内部的技术栈学习 1359

LVGL移植教程(正点原子)

学习正点原子LVGL移植教程,根据视频教程写的博客

papalila的博客 941

欧姆龙多PLC串行链接模式的应用

欧姆龙多PLC串行链接模式的应用 一、如何将两台CP1H进行串行PLC连接(PLC串行链接) 主机侧设定 从机侧设定 二、 如何实现编程通信 主机侧的【PC连接模式】为【全部】的时候 ① 主机会把自己的地址从3100开始,按照【链接字】设定的字数个数发送到每个从机的3100开始进行存储。 ② 从机会把自己的地址从31n0开始,按照主机侧参数【链接字】设定的字数个数发送到主机的31n0开始进行存储。 注:(n为从机的地址号,若从机号不连续,则该编号的地址将不被定义..

u014202847的博客 3087

JUC并发编程

JUC是什么?线程和进程并发、并行一些面试题Lock锁(重点) JUC是什么? JUC简称java util concurrent,是java中有关线程的三个包。 这里我们给出API文档 链接:https://pan.baidu.com/s/1k9s_96Ip8tnNug0NoTadmw 提取码:eexh 线程和进程 进程:运行中的应用程序***.exe的集合(QQ.exe、IDEA.exe) 从上图可以看出,线程数大于进程数。其实:一个进程往往包含多个线程,最少包含一个线程! java默认有2个.

熊二吃屁的博客 292

如何使用tinyalas接口从usb录音的同时从扬声器播放

3、 以上步骤确认完后,就可以修改tinyhostless.c程序,tinyhostless的本质就是边pcm_read(),边pcm_write();但原本tinyhostless只支持对同一声卡进行操作,所有需要修改其代码,改成录音和播放可支持不同声卡,如果是模拟声卡,有回环测试,可以实现边录边播放,但涉及USB声卡时,就没有现场的类似功能,有时候客户因为硬件特殊性,会有从USB录音的同时从扬声器播放出来的需求,本文简要描述如何使用tinyalsa接口实现该需求;

sdrgtywretyeruet的专栏 971

Java JUC

JAVA JUC1.Java JUC简介1-volatile关键字内存可见性volatile 关键字2-原子变量CAS算法CAS算法原子变量3-ConcurrentHashMap锁分段机制ConcurrentHashMap4-CountDownlatch闭锁CountDownlatch5-实现Callable接口Callable接口6-Lock同步锁显示锁Lock7-Condition控制线程通信Condition8-线程按需交替9-ReadWriteLock读写锁读-写锁ReadWriteLock10-线

qq_36705963的博客 1188

【异常】安装hermes-agent时Git克隆大仓库报错:error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: CAN

摘要:本文分析了Ubuntu服务器执行Git递归克隆时出现的网络传输中断错误(HTTP/2流异常关闭、数据截断)。主要原因是网络限制、协议兼容问题和缓冲区不足。提供了四种解决方案:1)扩大Git HTTP缓冲区;2)切换为HTTP/1.1协议;3)采用浅克隆+分步拉取子模块;4)网络优化措施。重点推荐浅克隆分步拉取作为最有效方案,所有方法无需重启即可生效,可快速解决大仓库递归克隆失败问题。

奶爸的编程之路,也就一周冷个三天 670

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Java进阶(Juc多线程并发)-进阶篇

11.线程池(重点) 12.四大函数式接口(必须掌握) 13.stream流式计算

luofengliubi的博客 311

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Java并发编程实战:JUC核心组件与高并发优化

并发编程是现代Java开发的核心技能,JUC(Java Util Concurrent)作为Java官方并发工具包,提供了原子变量、锁机制、并发集合等关键组件。其底层通过CAS(Compare-And-Swap)实现无锁编程,结合AQS(AbstractQueuedSynchronizer)框架构建了高效的同步机制。在高并发系统中,合理使用ReentrantLock、ConcurrentHashMap等组件可显著提升吞吐量,避免死锁问题。典型应用场景包括秒杀系统、实时交易等需要线程安全与高性能并存的领域。通

weixin_30315905的博客 315

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

[JUC-12] 分支合并框架

分支合并框架

学哥斌的博客 326
上一篇: JAVA多线程进阶篇 11、JUC线程池之ThreadPoolExecutor
下一篇: JAVA多线程进阶篇 13、JUC并发容器
悟空学编程
博客等级 码龄12年 32粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

悟空学编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值