ForkJoinPool

关于Java中ForkJoinPool.commonPool()详解 jdk8中的并行流parallelStream,CompletableFuture异步编程中有没有用到线程池? ForkJoinPool.commonPool()是什么?它的参数是固定的?还是程序可干预的? 阅读详情

ForkJoinPool

 

背景:ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行;当多个“小任务”执行完成之后,再将这些执行结果合并起来即可。这种思想值得学习。

 

使用:

Java7 提供了ForkJoinPool来支持将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合并成总的计算结果。

ForkJoinPool是ExecutorService的实现类,因此是一种特殊的线程池。

使用方法:创建了ForkJoinPool实例之后,就可以调用ForkJoinPool的submit(ForkJoinTask<T> task) 或invoke(ForkJoinTask<T> task)方法来执行指定任务了。

其中ForkJoinTask代表一个可以并行、合并的任务。ForkJoinTask是一个抽象类,它还有两个抽象子类:RecusiveAction和RecusiveTask。其中RecusiveTask代表有返回值的任务,而RecusiveAction代表没有返回值的任务。

下面的UML类图显示了ForkJoinPool、ForkJoinTask之间的关系:

 

 

demo:

以还行没有返回值的“大任务”(简单低打印1~300的数值)为例,程序将一个“大任务”拆分成多个“小任务”,并将任务交给ForkJoinPool来执行

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;

/**
 * ClassName:ForkJoinPoolAction <br/>
 * Function: 使用ForkJoinPool完成一个任务的分段执行
 * 简单的打印0-300的数值。用多线程实现并行执行
 * Date:     2017年12月4日 下午2:26:55 <br/>
 * @author   prd-lxw
 * @version   1.0
 * @since    JDK 1.7
 * @see      
 */
public class ForkJoinPoolAction {
    
    public static void main(String[] args) throws Exception{
        PrintTask task = new PrintTask(0, 300);
        //创建实例,并执行分割任务
        ForkJoinPool pool = new ForkJoinPool();
        pool.submit(task);
         //线程阻塞,等待所有任务完成
        pool.awaitTermination(2, TimeUnit.SECONDS);
        pool.shutdown();
    }
}

/**
 * ClassName: PrintTask <br/>
 * Function: 继承RecursiveAction来实现“可分解”的任务。
 * date: 2017年12月4日 下午5:17:41 <br/>
 *
 * @author prd-lxw
 * @version 1.0
 * @since JDK 1.7
 */
class PrintTask extends RecursiveAction{
    private static final int THRESHOLD = 50; //最多只能打印50个数
    private int start;
    private int end;
    
    

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



    @Override
    protected void compute() {
        
        if(end - start < THRESHOLD){
            for(int i=start;i<end;i++){
                System.out.println(Thread.currentThread().getName()+"的i值:"+i);
            }
        }else {
            int middle =(start+end)/2;
            PrintTask left = new PrintTask(start, middle);
            PrintTask right = new PrintTask(middle, end);
            //并行执行两个“小任务”
            left.fork();
            right.fork();
        }
        
    }
    
}

运行结果:

ForkJoinPool-1-worker-1的i值:262
ForkJoinPool-1-worker-7的i值:75
ForkJoinPool-1-worker-7的i值:76
ForkJoinPool-1-worker-5的i值:225
ForkJoinPool-1-worker-3的i值:187
ForkJoinPool-1-worker-6的i值:150
ForkJoinPool-1-worker-6的i值:151
ForkJoinPool-1-worker-6的i值:152
ForkJoinPool-1-worker-6的i值:153
ForkJoinPool-1-worker-6的i值:154

因为我的电脑是i7处理器,一共8个cpu,观察线程的名称可以发现,8个cpu都在运行。

通过RecursiveTask的返回值,来对一个长度为100的数组元素进行累加。

 

import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

/**
 * ClassName:ForJoinPollTask <br/>
 * Function: 对一个长度为100的元素值进行累加
 * Date:     2017年12月4日 下午5:41:46 <br/>
 * @author   prd-lxw
 * @version   1.0
 * @since    JDK 1.7
 * @see      
 */
public class ForJoinPollTask {

    public static void main(String[] args) throws Exception {
        int[] arr = new int[100];
        Random random = new Random();
        int total =0;
        //初始化100个数组元素
        for(int i=0,len = arr.length;i<len;i++){
            int temp = random.nextInt(20);
            //对数组元素赋值,并将数组元素的值添加到sum总和中
            total += (arr[i]=temp);
        }
        System.out.println("初始化数组总和:"+total);
        SumTask task = new SumTask(arr, 0, arr.length);
//        创建一个通用池,这个是jdk1.8提供的功能
        ForkJoinPool pool = ForkJoinPool.commonPool();
        Future<Integer> future = pool.submit(task); //提交分解的SumTask 任务
        System.out.println("多线程执行结果:"+future.get());
        pool.shutdown(); //关闭线程池
        
        

    }

}

/**
 * ClassName: SumTask <br/>
 * Function: 继承抽象类RecursiveTask,通过返回的结果,来实现数组的多线程分段累累加
 *  RecursiveTask 具有返回值
 * date: 2017年12月4日 下午6:08:11 <br/>
 *
 * @author prd-lxw
 * @version 1.0
 * @since JDK 1.7
 */
class SumTask extends RecursiveTask<Integer>{
    private static final int THRESHOLD = 20; //每个小任务 最多只累加20个数
    private int arry[];
    private int start;
    private int end;
    
    

    /**
     * Creates a new instance of SumTask.
     * 累加从start到end的arry数组
     * @param arry
     * @param start
     * @param end
     */
    public SumTask(int[] arry, int start, int end) {
        super();
        this.arry = arry;
        this.start = start;
        this.end = end;
    }



    @Override
    protected Integer compute() {
        int sum =0;
        //当end与start之间的差小于threshold时,开始进行实际的累加
        if(end - start <THRESHOLD){
            for(int i= start;i<end;i++){
                sum += arry[i];
            }
            return sum;
        }else {//当end与start之间的差大于threshold,即要累加的数超过20个时候,将大任务分解成小任务
            int middle = (start+ end)/2;
            SumTask left = new SumTask(arry, start, middle);
            SumTask right = new SumTask(arry, middle, end);
            //并行执行两个 小任务
            left.fork();
            right.fork();
            //把两个小任务累加的结果合并起来
            return left.join()+right.join();
        }
        
    }
    
}

执行结果:

初始化数组总和:1008
多线程执行结果:1008

 

分析和总结:

在Java 7中引入了一种新的线程池:ForkJoinPool。

它同ThreadPoolExecutor一样,也实现了Executor和ExecutorService接口。它使用了一个无限队列来保存需要执行的任务,而线程的数量则是通过构造函数传入,如果没有向构造函数中传入希望的线程数量,那么当前计算机可用的CPU数量会被设置为线程数量作为默认值。

ForkJoinPool主要用来使用分治法(Divide-and-Conquer Algorithm)来解决问题。典型的应用比如快速排序算法。

这里的要点在于,ForkJoinPool需要使用相对少的线程来处理大量的任务。

比如要对1000万个数据进行排序,那么会将这个任务分割成两个500万的排序任务和一个针对这两组500万数据的合并任务。以此类推,对于500万的数据也会做出同样的分割处理,到最后会设置一个阈值来规定当数据规模到多少时,停止这样的分割处理。比如,当元素的数量小于10时,会停止分割,转而使用插入排序对它们进行排序。

那么到最后,所有的任务加起来会有大概2000000+个。问题的关键在于,对于一个任务而言,只有当它所有的子任务完成之后,它才能够被执行。

所以当使用ThreadPoolExecutor时,使用分治法会存在问题,因为ThreadPoolExecutor中的线程无法像任务队列中再添加一个任务并且在等待该任务完成之后再继续执行。而使用ForkJoinPool时,就能够让其中的线程创建新的任务,并挂起当前的任务,此时线程就能够从队列中选择子任务执行。

 

以上程序的关键是fork()和join()方法。在ForkJoinPool使用的线程中,会使用一个内部队列来对需要执行的任务以及子任务进行操作来保证它们的执行顺序。

那么使用ThreadPoolExecutor或者ForkJoinPool,会有什么性能的差异呢?

首先,使用ForkJoinPool能够使用数量有限的线程来完成非常多的具有父子关系的任务,比如使用4个线程来完成超过200万个任务。但是,使用ThreadPoolExecutor时,是不可能完成的,因为ThreadPoolExecutor中的Thread无法选择优先执行子任务,需要完成200万个具有父子关系的任务时,也需要200万个线程,显然这是不可行的。

ps:ForkJoinPool在执行过程中,会创建大量的子任务,导致GC进行垃圾回收,这些是需要注意的。

 

转自:https://www.cnblogs.com/lixuwu/p/7979480.html

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

相关推荐

ForkJoinPool介绍

目录: 一、 使用到的methods 二、 前提介绍 三、 内容理解 四、 几个重要的点 五、 实例 正文: 一、 本章节主要用到的methods有:fork(), join(), compute() 二、 前提介绍: ThreadPool Thread pool包含了: (1) threads:相当于执行任务的工人 (2) 排队等着被执行的tasks:相当于被执行的任务 tasks在ThreadPool中是以Queue的形式存在。最先放进Queue的task最后被thread执行(FILO)。

qq_39579301的博客 684

【第十五篇】ForkJoinPool的使用及基本原理【重点】

1.1 概述 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架。ForkJoinPool是Java中提供了一个线程池,特点是用来执行分治任务。主题思想是将大任务分解为小任务,然后继续将小任务分解,直至能够直接解决为止,然后再依次将任务的结果合并。 1.2 原理详解   ForkJoinPool是自java7开始,jvm提供的一个用于并行执行的任务框架。其主旨是将大任务分成若干小任务,之后再并行对这些小任务进行计算,最终汇总这些任务的结果。得到最终的结果。其广泛用在java8的stream

ᶻᶻᶻ 枕星河的博客 1万+

死磕 java线程系列之ForkJoinPool深入解析

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 注:本文基于ForkJoinPool分治线程池类。 简介 随着在硬件上多核处理器的发展和广泛使用,并发编程成为程序员必须掌握的一门技术,在面试中也经常考查面试者并发相关的知识。 今天,我们就来看一道面试题: 如何充分利用多核CPU,计算很大数组中所有整数的和? 剖析 单线程相加? 我们最容易想到...

彤哥读源码 1912

线程池之ForkJoinPool

概述 ForkJoinPool分支/合并框架,就是在必要的情况下,将一个大任务拆分(fork)成若干个小任务(拆到不能再拆为止),在将一个个的小任务运算的结果进行Join汇总。

抽象的螺旋 8710

从翼型到湍流:用生活化案例图解空气动力学核心概念(中英双语版)

本文通过飞机机翼、F1赛车、高尔夫球等生活化案例,图解空气动力学核心概念。深入浅出地解释了攻角如何产生升力、边界层与流动分离如何影响阻力、马赫数如何划分速度世界,以及涡流与湍流的特性与应用。文章还介绍了计算流体动力学(CFD)这一现代数字风洞工具,帮助读者直观理解这些塑造现代交通与运动设计的无形之力。

metaverse5vr的博客 475

老N卡福音:GT1030/GTX1050在MacOS Ventura 13.2上的完整驱动指南(附实测截图)

本文详细介绍了如何在MacOS Ventura 13.2上通过OCLP工具链驱动GT1030和GTX1050等老款NVIDIA显卡,涵盖硬件兼容性验证、BIOS设置、OpenCore配置、驱动安装及性能测试全流程。实测数据显示,这些基于Pascal和Maxwell架构的显卡在当代MacOS系统中仍能发挥实用价值,为老N卡用户提供完整解决方案。

weixin_30832143的博客 632

介绍 ForkJoinPool 的适用场景,实现原理

本文的主要目的是介绍 ForkJoinPool 的适用场景,实现原理,以及示例代码。 说在前面 可以说是说明,也可以说下面是结论: ForkJoinPool 不是为了替代 ExecutorService,而是它的补充,在某些应用场景下性能比 ExecutorService 更好。 ForkJoinPool 主要用于实现“分而治之”的算法,特别是分治之后递归调用的函数,例如 quick sort 等...

大大肉包博客 8万+

模仿学习与强化学习结合(IL+RL)有没有代表性论文?未来发展趋势如何?

IL与RL的结合正成为AI研究热点,尤其在机器人控制、复杂博弈等需要边学边练的场景。经典方法如Dagger(2010)和GAIL(2016)开创了先用模仿学习预热、再用强化学习微调的模式。近期工作如IN-RIL(2024)提出交替训练策略,显著提升样本效率。开源项目RoboSchool和StableBaselines3为相关研究提供支持。未来趋势包括:1)混合式智能体结合人类经验与自主探索;2)突破小样本学习、自然语言交互等方向;3)提升安全性、样本效率和可解释性。

CyberSoma的博客 2249

ForkJoinPool 详解

背景:ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行;当多个“小任务”执行完成之后,再将这些执行结果合并起来即可。这种思想值得学习。 使用 Java7 提供了ForkJoinPool来支持将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合并成总的计算结...

程序丸 6216

大数据之VIP(Virtual IP,虚拟IP)负载均衡

VIP(Virtual IP,虚拟IP)负载均衡是一种在计算机网络中常用的技术,用于将网络请求流量均匀地分散到多个服务器上,以提高系统的可扩展性、可靠性和性能。

赵玉的专栏 4124

基于Python的上市公司年报PDF文本抓取与财务风险分析系统

随着大数据时代的到来,金融数据分析已成为投资决策和风险管理的重要工具。上市公司年报包含了丰富的财务信息和经营数据,通过对这些数据的提取和分析,可以评估公司的财务状况和潜在风险。本文将详细介绍如何使用Python构建一个完整的上市公司年报文本抓取与财务风险分析系统,涵盖PDF文本提取、数据清洗、财务指标计算和风险分析等全流程。

2201_76125261的博客 312

ForkJoinPool简介

(2023年3月公司内部分享)本文是主要基于以下三篇文章摘录和整理,屏蔽了一些细节,主要讲基本原理和任务处理流程,具体细节可以先看原文:ForkJoinPool大型图文现场(一阅到底 vs 直接收藏)(上)ForkJoinPool大型图文现场(一阅到底 vs 直接收藏)(中)ForkJoinPool大型图文现场(一阅到底 vs 直接收藏)(下)在计算机科学中,分治法是一种很重要的算法。字面上的解释是「分而治之」,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子

huachangzai的博客 1101

工业相机——靶面尺寸、像元尺寸、分辨率 、传感器尺寸

由Sensor对角线长度表示,单位英寸,这里的1英寸=16mm。——靶面尺寸为宽12.7mm*高9.6mm,对角线16mm。——靶面尺寸为宽8.8mm*高6.6mm,对角线11mm。——靶面尺寸为宽7.2mm*高5.4mm,对角线9mm。——靶面尺寸为宽6.4mm*高4.8mm,对角线8mm。——靶面尺寸为宽4.8mm*高3.6mm,对角线6mm。——靶面尺寸为宽3.2mm*高2.4mm,对角线4mm。——靶面尺寸为宽14*高10.5mm,对角线17mm。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 9607

ForkJoinPool入门篇

《线程池ThreadPoolExecutor详解》和《任务调度线程池ScheduledThreadPoolExecutor》两篇文章将ThreadPoolExecutor和ScheduledThreadPoolExecutor两个核心线程池已经详细介绍过了,它们整体的工作结构如下图所示。 这篇文章将介绍最后一个线程池——Java7中最引人瞩目的ForkJoinPool线程池。 1. 为...

优快云文章已停止维护,后续文章会在 https://blog.hufeifei.cn 持续更新 1万+

【AI应用实战-OpenCode】OpenCode安装部署(一)

OpenCode是一款2026年流行的开源AI编程工具,兼具轻量代码编辑器和智能编码代理功能。其核心优势包括:完全免费开源(MIT协议)、全平台兼容、支持75+大模型(含本地部署)、内置完整编程功能链(代码补全/Git集成/AI调试等),且所有数据本地存储确保隐私安全。相比Copilot等商业工具,OpenCode提供更自由的模型选择和零门槛使用体验。安装要求Windows10+/macOS12+/Linux主流发行版,仅需200MB空间和4G内存。该工具完美兼容VSCode生态,支持终端/桌面/IDE三种

2430

Android Treble 简介

上面两段话来自官网上,Android 8.0 重新设计了 Android 操作系统框架(在一个名为“Treble”的项目中),以便让制造商能够以更低的成本更轻松、更快速地将设备更新到新版 Android 系统。本文主要整理一下Android Treble框架。

私房菜 9275

ForkJoinPool线程池

在Java 7中引入了一种新的线程池:ForkJoinPool。 它同ThreadPoolExecutor一样,也实现了Executor和ExecutorService接口。它使用了一个无限队列来保存需要执行的任务,而线程的数量则是通过构造函数传入,如果没有向构造函数中传入希望的线程数量,那么当前计算机可用的CPU数量会被设置为线程数量作为默认值。 ForkJoinPool主要用来使用分治法(...

侠客小虎的博客 8521

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

什么是 ForkJoinPool

详细讲解 ForkJoinPool 的概念、工作原理以及如何使用它

一个public的class的博客 1069

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

ForkJoinPool源码全面解析

ForkJoinPool源码全面解析 文章目录ForkJoinPool源码全面解析前言一、前奏1.0 ForkJoinPool1.1 ctl二、使用步骤1.引入库2.读入数据总结 前言 前前后后花了几天时间才把这东西分析完,吐槽一下,这框架源码不是一般的难看,里面的变量名全是 a、j、k这种单个字母命名的,一不小心就容易看叉批了,里面的注释写了和没写差不多,不过好在代码不算多,最终还是慢慢看完了,不过这框架是真的强,有很多工作中可以借鉴的地方。 想要完全看懂ForkJoinPool源码的同学,只需要对位

Mark2527的博客 2226

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

ForkJoinPool和ThreadPoolExecutor区别

ForkJoinPool和ThreadPoolExecutor的主要区别体现在任务执行的方式和适用的场景上。

刘皇叔说Java的博客 2144

ForkJoinPool与ThreadPoolExecutor的对比与选择

除了通用的ThreadPoolExecutor之外,Java还提供了一个有特殊用途的线程池,即ForkJoinPool。这个类跟ThreadPoolExecutor类大体相似,实现了Executor和ExecutorService接口。当使用这些接口的时候,ForkJoinPool会使用一个无界队列来存储任务,这些任务由线程池构造函数中指定的线程数执行。如果没有设置线程数的话,则默认使用当前机器可用CPU数或者Docker容器中配置的CPU数大小的线程数量。 ForkJoinPool往往用于实现分治算法,

m0_37173810的博客 5789

ForkJoinPool初略分析

之前曾经分析过线程池,在Jdk1.7中出现了一种新的线程池ForkJoinPool,Java8中的parallelStream API就是基于ForkJoinPool实现的,它和普通的线程池不太一样,本文来分析下ForkJoinPool内部运行原理。 本来想着直接分析parallelStream,看了半天看不懂,果然学习没有捷径啊… 为什么要有ForkJoinPool: 计算机...

淡定一生2333的博客 6903

forkjoin和forkjoinpool讲解

forkjoin和forkjoinpool讲解背景为什么需要forkjoin先看代码结合多线程理解forkjoin代码forkjoin主要的类forkjoin常用方法forkjoin设计原理forkjoin整体工作流程工作队列和线程池 背景  对于java开发从业人员来说,并发编程是绕不开的话题,juc并发包下提供了一系列多线程场景解决方案。  随着jdk1.8的普及,多线程处理问题,除了使用使用线程池(ExecutorService),很多人选择了parallelStream() 并行流,底层使用fork

zjy_love_java的博客 9414

ForkJoinPool详解

ForkJoinPool详解

weixin_45428910的博客 1019
上一篇: 积累
下一篇: Spring积累
Art&Code
博客等级 码龄7年 77粉丝 554原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值