Fork/Join框架

Java~ForkJoinPool + parallelStream实现并行快速处理数据流 文章目录ForkJoinPoolinvoke、execute和submit区别parallelStream实现快速处理数据流 ForkJoinPool 说起ForkJoinPool先说Fork/Join框架 我们通过Fork和Join这两个单词来理解一下Fork/Join框架。Fork就是把一个大任务切分 为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结 果。比如计算1+2+…+10000,可以分割成10个子任务,每个子任务分别对1000个数进行求和, 最终汇总这10个子 阅读详情

一、引言

算法领域有一种基本思想叫做“分治”,所谓“分治”就是将一个难以直接解决的大问题,分割成一些规模较小的子问题,以便各个击破,分而治之。

比如:对于一个规模为N的问题,若该问题可以容易地解决,则直接解决;否则将其分解为K个规模较小的子问题,这些子问题互相独立且与原问题性质相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解,这种算法设计策略叫做分治法。

许多基础算法都运用了“分治”的思想,比如二分查找、快速排序等等。

基于“分治”的思想,J.U.C在JDK1.7时引入了一套Fork/Join框架。Fork/Join框架的基本思想就是将一个大任务分解(Fork)成一系列子任务,子任务可以继续往下分解,当多个不同的子任务都执行完成后,可以将它们各自的结果合并(Join)成一个大结果,最终合并成大任务的结果:

在这里插入图片描述

二、工作窃取算法

从上述Fork/Join框架的描述可以看出,我们需要一些线程来执行Fork出的任务,在实际中,如果每次都创建新的线程执行任务,对系统资源的开销会很大,所以Fork/Join框架利用了线程池来调度任务。

另外,这里可以思考一个问题,既然由线程池调度,根据我们之前学习线程池的经验,必然存在两个要素:

  • 工作线程
  • 任务队列

一般的线程池只有一个任务队列,但是对于Fork/Join框架来说,由于Fork出的各个子任务其实是平行关系,为了提高效率,减少线程竞争,应该将这些平行的任务放到不同的队列中去,如上图中,大任务分解成三个子任务:子任务1、子任务2、子任务3,那么就创建三个任务队列,然后再创建3个工作线程与队列一一对应。

由于线程处理不同任务的速度不同,这样就可能存在某个线程先执行完了自己队列中的任务的情况,这时为了提升效率,我们可以让该线程去“窃取”其它任务队列中的任务,这就是所谓的工作窃取算法。

“工作窃取”的示意图如下,当线程1执行完自身任务队列中的任务后,尝试从线程2的任务队列中“窃取”任务:

在这里插入图片描述

对于一般的队列来说,是按照队列先进先出执行的,要满足“工作窃取”的需求,任务队列应该支持从“队尾”出队元素,这样可以减少与其它工作线程的冲突(因为正常情况下,其它工作线程从“队首”获取自己任务队列中的任务),满足这一需求的任务队列其实就是我们在juc-collections框架中介绍过的双端阻塞队列——LinkedBlockingDeque。
当然,出于性能考虑,J.U.C中的Fork/Join框架并没有直接利用LinkedBlockingDeque作为任务队列,而是自己重新实现了一个。

三、使用示例

为了给接下来的分析F/J框架组件做铺垫,我们先通过一个简单示例看下Fork/Join框架的基本使用。

假设有个非常大的long[]数组,通过FJ框架求解数组所有元素的和。
任务类定义,因为需要返回结果,所以继承RecursiveTask,并覆写compute方法。任务的fork通过ForkJoinTask的fork方法执行,join方法方法用于等待任务执行后返回:

public class ArraySumTask extends RecursiveTask<Long> {
 
    private final int[] array;
    private final int begin;
    private final int end;
 
    private static final int THRESHOLD = 100;
 
    public ArraySumTask(int[] array, int begin, int end) {
        this.array = array;
        this.begin = begin;
        this.end = end;
    }
 
    @Override
    protected Long compute() {
        long sum = 0;
 
        if (end - begin + 1 < THRESHOLD) {      // 小于阈值, 直接计算
            for (int i = begin; i <= end; i++) {
                sum += array[i];
            }
        } else {
            int middle = (end + begin) / 2;
            ArraySumTask subtask1 = new ArraySumTask(this.array, begin, middle);
            ArraySumTask subtask2 = new ArraySumTask(this.array, middle + 1, end);
 
            subtask1.fork();
            subtask2.fork();
 
            long sum1 = subtask1.join();
            long sum2 = subtask2.join();
 
            sum = sum1 + sum2;
        }
        return sum;
    }
}

调用方如下:

public class Main {
    public static void main(String[] args) {
        ForkJoinPool executor = new ForkJoinPool();
        ArraySumTask task = new ArraySumTask(new int[10000], 0, 9999);
 
        ForkJoinTask future = executor.submit(task);
 
        // some time passed...
 
        if (future.isCompletedAbnormally()) {
            System.out.println(future.getException());
        }
 
        try {
            System.out.println("result: " + future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
 
    }
}

注意:ForkJoinTask在执行的时候可能会抛出异常,但是没办法在主线程里直接捕获异常,所以ForkJoinTask提供了isCompletedAbnormally()方法来检查任务是否已经抛出异常或已经被取消了,并且可以通过ForkJoinTask的getException方法获取异常.

四、核心组件

在前几小节中,我们简要介绍了Fork/Join框架和它的使用。本节我们将更进一步,深入F/J框架,了解它的各个组件的关系和核心设计思想,本节不会涉及太多的源码分析,而是参考 Doug Lea的这篇论文《A Java Fork/Join Framework》,从宏观上分析F/J框架,然后分析整个框架的调度流程,阅读完本节后,在下一节——Fork/Join框架(2) 实现中,我们再去深入源码会轻松很多。

F/J框架的实现非常复杂,内部大量运用了位操作和无锁算法,撇开这些实现细节不谈,该框架主要涉及三大核心组件:ForkJoinPool(线程池)、ForkJoinTask(任务)、ForkJoinWorkerThread(工作线程),外加WorkQueue(任务队列):

  • ForkJoinPool:ExecutorService的实现类,负责工作线程的管理、任务队列的维护,以及控制整个任务调度流程;
  • ForkJoinTask:Future接口的实现类,fork是其核心方法,用于分解任务并异步执行;而join方法在任务结果计算完毕之后才会运行,用来合并或返回计算结果;
  • ForkJoinWorkerThread:Thread的子类,作为线程池中的工作线程(Worker)执行任务;
  • WorkQueue:任务队列,用于保存任务;

ForkJoinPool

ForkJoinPool作为Executors框架的一员,从外部看与其它线程池并没有什么区别,仅仅是ExecutorService的一个实现类:

ForkJoinPool的主要工作如下:

  • 接受外部任务的提交(调用ForkJoinPool的invoke/execute/submit方法提交任务);
  • 接受ForkJoinTask自身fork出的子任务的提交;
  • 任务队列数组(WorkQueue[])的初始化和管理;
  • 作线程(Worker)的创建/管理。
    注意:ForkJoinPool提供了3类外部提交任务的方法:invoke、execute、submit,它们的主要区别在于任务的执行方式上。
  • 通过invoke方法提交的任务,调用线程直到任务执行完成才会返回,也就是说这是一个同步方法,且有返回结果;
  • 通过execute方法提交的任务,调用线程会立即返回,也就是说这是一个异步方法,且没有返回结果;
  • 通过submit方法提交的任务,调用线程会立即返回,也就是说这是一个异步方法,且有返回结果(返回Future实现类,可以通过get获取结果)。

ForkJoinPool对象的构建有两种方式:

  • 通过3种构造器的任意一种进行构造;
  • 通过ForkJoinPool.commonPool()静态方法构造。JDK8提供的,主要是为了简化线程池的构建

ForkJoinPool对外提供的3种构造器,其实最终都调用了下面这个构造器:

/**
 * @param parallelism      并行级别, 默认为CPU核心数
 * @param factory          工作线程工厂
 * @param handler          异常处理器
 * @param mode        调度模式: true表示FIFO_QUEUE; false表示LIFO_QUEUE
 * @param workerNamePrefix 工作线程的名称前缀
 */
private ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory, UncaughtExceptionHandler handler,int mode, String workerNamePrefix) {
    this.workerNamePrefix = workerNamePrefix;
    this.factory = factory;
    this.ueh = handler;
    this.config = (parallelism & SMASK) | mode;
    long np = (long) (-parallelism); // offset ctl counts
    this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);

}

parallelism:默认值为CPU核心数,ForkJoinPool里工作线程数量与该参数有关,但它不表示最大线程数;
factory:工作线程工厂,默认是DefaultForkJoinWorkerThreadFactory,其实就是用来创建工作线程对象——ForkJoinWorkerThread;
handler:异常处理器;
config:保存parallelism和mode信息,供后续读取;
ctl:线程池的核心控制字段
这些入参目前不用关注,我们重点是mode这个字段,ForkJoinPool支持两种模式:

  • 同步模式(默认方式)
  • 异步模式
mode = asyncMode ? FIFO_QUEUE : LIFO_QUEUE

注意:这里的同步/异步并不是指F/J框架本身是采用同步模式还是采用异步模式工作,而是指其中的工作线程的工作方式。在F/J框架中,每个工作线程(Worker)都有一个属于自己的任务队列(WorkQueue),这是一个底层采用数组实现的双向队列。
同步是指:对于工作线程(Worker)自身队列中的任务,采用栈方式执行;异步是指:对于工作线程(Worker)自身队列中的任务,采用队列的方式执行。

ForkJoinTask

从Fork/Join框架的描述上来看,“任务”必须要满足一定的条件:

支持Fork,即任务自身的分解
支持Join,即任务结果的合并
因此,J.U.C提供了一个抽象类——ForkJoinTask,来作为该类Fork/Join任务的抽象定义:

ForkJoinTask实现了Future接口,是一个异步任务,我们在使用Fork/Join框架时,一般需要使用线程池来调度任务,线程池内部调度的其实都是ForkJoinTask任务(即使提交的是一个Runnable或Callable任务,也会被适配成ForkJoinTask)。

除了ForkJoinTask,Fork/Join框架还提供了两个它的抽象实现,我们在自定义ForkJoin任务时,一般继承这两个类:

  • RecursiveAction:表示没有返回结果的ForkJoin任务
  • RecursiveTask:表示有返回结果的ForkJoin任务
public abstract class RecursiveAction extends ForkJoinTask<Void> {
    /**
     * 该任务的执行,子类覆写该方法
     */
    protected abstract void compute();
 
    public final Void getRawResult() { return null; }
 
    protected final void setRawResult(Void mustBeNull) { }
 
    protected final boolean exec() {
        compute();
        return true;
    }
}
public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
 
    /**
     * 该任务的执行结果.
     */
    V result;
 
    /**
     * 该任务的执行,子类覆写该方法
     */
    protected abstract V compute();
 
    public final V getRawResult() {
        return result;
    }
 
    protected final void setRawResult(V value) {
        result = value;
    }
 
    protected final boolean exec() {
        result = compute();
        return true;
    }

}

ForkJoinTask除了和ForkJoinPool 结合使用外,也可以单独使用,当我们调用ForkJoinTask的fork方法时,其内部会通过ForkJoinPool.commonPool()方法创建线程池,然后将自己作为任务提交给线程池。

ForkJoinWorkerThread

Fork/Join框架中,每个工作线程(Worker)都有一个自己的任务队列(WorkerQueue), 所以需要对一般的Thread做些特性化处理,J.U.C提供了ForkJoinWorkerThread类作为ForkJoinPool中的工作线程:

public class ForkJoinWorkerThread extends Thread {
    
    final ForkJoinPool pool;                    // 该工作线程归属的线程池
    final ForkJoinPool.WorkQueue workQueue;     // 对应的任务队列
 
    protected ForkJoinWorkerThread(ForkJoinPool pool) {
        super("aForkJoinWorkerThread");         // 指定工作线程名称
        this.pool = pool;
        this.workQueue = pool.registerWorker(this);
    }
  
    // ...
}

ForkJoinWorkerThread 在构造过程中,会保存所属线程池信息和与自己绑定的任务队列信息。同时,它会通过ForkJoinPool的registerWorker方法将自己注册到线程池中。

线程池中的每个工作线程(ForkJoinWorkerThread)都有一个自己的任务队列(WorkQueue),工作线程优先处理自身队列中的任务(LIFO或FIFO顺序,由线程池构造时的参数 mode 决定),自身队列为空时,以FIFO的顺序随机窃取其它队列中的任务。

WorkQueue

任务队列(WorkQueue)是ForkJoinPool与其它线程池区别最大的地方,在ForkJoinPool内部,维护着一个WorkQueue[]数组,它会在外部首次提交任务)时进行初始化:

volatile WorkQueue[] workQueues; // main registry

当通过线程池的外部方法(submit、invoke、execute)提交任务时,如果WorkQueue[]没有初始化,则会进行初始化;然后根据数组大小和线程随机数(ThreadLocalRandom.probe)等信息,计算出任务队列所在的数组索引(这个索引一定是偶数),如果索引处没有任务队列,则初始化一个,再将任务入队。也就是说,通过外部方法提交的任务一定是在偶数队列,没有绑定工作线程。
WorkQueue作为ForkJoinPool的内部类,表示一个双端队列。双端队列既可以作为栈使用(LIFO),也可以作为队列使用(FIFO)。ForkJoinPool的“工作窃取”正是利用了这个特点,当工作线程从自己的队列中获取任务时,默认总是以栈操作(LIFO)的方式从栈顶取任务;当工作线程尝试窃取其它任务队列中的任务时,则是FIFO的方式。

我们在ForkJoinPool一节中曾讲过,可以指定线程池的同步/异步模式(mode参数),其作用就在于此。同步模式就是“栈操作”,异步模式就是“队列操作”,影响的就是工作线程从自己队列中取任务的方式。
ForkJoinPool中的工作队列可以分为两类:

  • 有工作线程(Worker)绑定的任务队列:数组下标始终是奇数,称为task queue,该队列中的任务均由工作线程调用产生(工作线程调用FutureTask.fork方法);
  • 没有工作线程(Worker)绑定的任务队列:数组下标始终是偶数,称为submissions queue,该队列中的任务全部由其它线程提交(也就是非工作线程调用execute/submit/invoke或者FutureTask.fork方法)。

六、总结

本章简要概述了Fork/Join框架的思想、主要组件及基本使用,Fork/Join框架的核心包含四大组件:ForkJoinTask任务类、ForkJoinPool线程池、ForkJoinWorkerThread工作线程、WorkQueue任务队列。

本章通过示例,描述了各个组件的关系以及ForkJoin线程池的整个调度流程,F/J框架的核心来自于它的工作窃取及调度策略,可以总结为以下几点:

  • 每个Worker线程利用它自己的任务队列维护可执行任务;
  • 任务队列是一种双端队列,支持LIFO的push和pop操作,也支持FIFO的take操作;
  • 任务fork的子任务,只会push到它所在线程(调用fork方法的线程)的队列;
  • 工作线程既可以使用LIFO通过pop处理自己队列中的任务,也可以FIFO通过poll处理自己队列中的任务,具体取决于构造线程池时的asyncMode参数;
  • 当工作线程自己队列中没有待处理任务时,它尝试去随机读取(窃取)其它任务队列的base端的任务;
  • 当线程进入join操作,它也会去处理其它工作线程的队列中的任务(自己的已经处理完了),直到目标任务完成(通过isDone方法);
  • 当一个工作线程没有任务了,并且尝试从其它队列窃取也失败了,它让出资源(通过使用yields, sleeps或者其它优先级调整)并且随后会再次激活,直到所有工作线程都空闲了——此时,它们都阻塞在等待另一个顶层线程的调用。
Fork/Join工作原理解析 一、如何高效利用CPU 在介绍Fork/Join框架之前,思考一个问题,在多线程的情况下,如何才能高效的利用CPU,以常用的线程池为例,线程池的线程数设置多少合适? 通常调整线程池中的线程数量其核心目的就是为了能够充分的利用CPU和内存资源,从而最大限度的提高程序的性能。在实际工作中,我们可能会根据任务类型的不同而采取不同的策略。按照一个任务执行过程中使用CPU的时间和任务总耗时的比例,可以将任务分为两种:CPU密集型任务和IO密集型任务 1.1 任务类型 1.1.1 CPU密集型任务 CPU密集型任务也称 阅读详情

相关推荐

Fork/Join 框架详解

Fork/Join 是一种并行计算模式,用于解决可以被分解成更小的可并行任务的问题。该模式包含两个关键操作:Fork(分解)和Join(合并)。在 Fork/Join 模式中,原始问题被递归地分解为更小的子问题,直到达到可以并行解决的最小单位。这个过程被称为 Fork。每个子问题可以独立地在不同的处理器上执行,并行地求解部分问题。一旦所有的子问题都被解决,就会进行 Join 操作。Join 操作将所有子问题的结果合并为最终的解决方案。

swadian2008的博客 4635

并发编程之ForkJoin使用及原理

以forkJoin的一个使用情景开始吧 public class ForkJoinQuery extends RecursiveTask<Boolean> { private static final int THREAD_HOLD = 5000; private long start; private long end;//需要查询的所有数据的数量 private...

CoffeeAndMilk123的博客 564

世界坐标系/相机坐标系/图像坐标系 转换

目录一、各坐标系简要介绍二、坐标系转换2.1 世界坐标系转为相机坐标系2.2 相机坐标系转为物理图像坐标系2.3 物理图像坐标系转为图像坐标系2.4 总结2.5 为什么要使用齐次坐标参考文献 一、各坐标系简要介绍 首先介绍数字图像处理领域中的图像坐标系,如上图左图所示,坐标系O_0为图像坐标系,其原点是在图像的左上角,每一个像素通过其所在位置的列数和行数索引 (u,v) 来表示。 另外需要建立图像坐标与物理单位的关系,而后才能将目标的真实世界坐标转换为图像坐标。即建立以物理单位表示的物理图像坐标系(有些文

流觞时光 1万+

多线程 ForkJoinPool

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

weixin_33863087的博客 2133

ThinkBook 16 2024 Ubuntu驱动全攻略:从无线网卡到触控板

本文详细介绍了ThinkBook 16 2024在Ubuntu系统下的驱动问题解决方案,涵盖无线网卡、蓝牙、显卡和触控板等关键硬件的驱动修复步骤。通过具体命令和配置指南,帮助用户快速解决兼容性问题,提升Ubuntu在ThinkBook上的使用体验。

weixin_29200741的博客 826

YOLOv11多模态融合实战:基于YOLOFuse的RGB与红外线(IR)协同检测技术解析

本文深入解析了基于YOLOv11的YOLOFuse多模态融合技术,重点探讨了RGB与红外线(IR)协同检测的实现原理与实战应用。文章详细介绍了双流架构与数据级、特征级、决策级三种融合策略,并通过实战案例展示了其在低光照、复杂环境下显著提升检测精度与鲁棒性的优势,为全天候安防、自动驾驶等场景提供了有效的技术解决方案。

weixin_29041195的博客 648

线程池讲解

线程池

m0_57485150的博客 2812

用Python+Charles搞定小程序付费短剧下载(附完整代码与避坑点)

本文详细介绍了如何利用Python和Charles抓包工具实现小程序付费短剧的自动化下载。通过分析小程序视频接口、破解请求参数,并编写Python脚本,读者可以轻松获取并保存短剧内容。文章还提供了完整的代码示例和常见问题的解决方案,特别适合对视频采集和抓包技术感兴趣的开发者。

weixin_28731231的博客 1187

Fork/join框架

1 Frok/Join框架简介 Fork/Join框架是Java7提供了的一个用于并行执行的任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 Fork 递归地将任务分解为较小的独立子任务,直到它们足够简单以便异步执行。 Join 将所有子任务的结果递归地连接成单个结果,或者在返回void的任务的情况下,程序只是等待每个子任务执行完毕。 比如计算 1+2+......+10000,可以分割成10个子任务,每个子任务对1000个数进行求和,最终汇

leimeng123的博客 3934

二阶系统的带宽(频域分析)

下面以典型I型系统为例,计算系统的开环截止频率和闭环截止频率。设I型系统为: 1:系统的开环截止频率为 2:系统的闭环截止频率 其实我们在工程整定时,把ζ = 0.707,也把系统的带宽近视看成自然震荡角频率即 (wb≈wc≈wnw_{b}\approx w_{c}\approx w_{n}wb​≈wc​≈wn​)对于二阶系统。 ...

wanrenqi的博客 2万+

K8s(二十一):在 Kubernetes 集群中部署 MySQL8.0 高可用集群(1主2从)

🔴 K8s(二十一):在 Kubernetes 集群中部署 MySQL8.0 高可用集群(1主2从)

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 3万+

Fork/Join 框架

本文部分摘自《Java 并发编程的艺术》 Fork/Join 框架概述 Fork/Join 框架是 Java7 提供的一个用于并行执行任务的框架,是把一个大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架,其运行流程如图所示: 工作窃取算法 工作窃取算法是指某个线程从其他队列里窃取任务来执行,为什么要这样做呢?假如我们需要做一个比较大的任务,可以把这个任务分割为若干个互不依赖的子任务,为了减少线程间的竞争,把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行..

低吟不作语的博客 539

PCL RANSAC拟合直线并插值

空间直线线性插值的原理与实现方法。

点云侠的博客 136

Fork/Join - 并发框架源码解析

什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。比如计算1+2+ … +100...

.... 永远年轻,永远热泪盈眶 5万+

LE AUDIO---Volume Control Service

LE AUDIO---Volume Control Service

weixin_42162924的博客 162

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

细说Fork/Join框架

什么是Fork/Join框架?Fork/Join框架是JDK1.7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干小任务,最终汇总每个小任务结果后得到大任务结果...

田维常 640

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

java之Fork/Join框架

java之Fork/join框架

qq_41820066的博客 951

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

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

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Fork/Join框架简介

1 引子 Fork/Join框架是从Java1.7开始提供的一个并行处理任务的框架(本篇博客基于JDK1.8分析),它的基本思路是将一个大任务分解成若干个小任务,并行处理多个小任务,最后再汇总合并这些小任务的结果便可得到原来的大任务结果。 从字面意思来理解Fork/Join框架,"Fork"表示“分叉”,它把大任务分解成多个小任务并行处理,而“Join”表示“联合”,它将这些小任务的结果...

小伍的程序之路 748

Fork/Join框架 分而治之

什么是双亲委派机制 当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。 类加载器的类别 BootstrapClassLoader(启动类加载器) c++编写,加载java核心库 java.*,构造ExtClassLoader和AppClassLoader。由于引导类加载器涉及到虚拟机本地实现...

m0_37235955的博客 238

Java中的Fork/Join框架

在当今快速发展的科技时代,实时数据处理成为了大数据领域的一个关键需求。传统的批处理框架已经难以应对日益增长的数据量和复杂的实时处理需求。而Apache Flink作为一种新兴的分布式流处理引擎,以其强大的实时数据处理能力和灵活的编程模型,迅速在Java开发者社区中崭露头角。Apache Flink是一个用于处理数据流和批处理数据的开源框架。它最初是由德国柏林的技术大学开发的一个研究项目,后来逐渐发展成为一个完整的流处理解决方案。

weixin_46372265的博客 889

Fork/Join框架介绍

1、Fork/Join框架是什么 Fork/Join框架是一个比较特殊的线程池框架,专用于需要将一个任务不断分解成多个子任务(分支),并将多个子任务的结果不断进行汇总得到最终结果(聚合)的并行计算框架。 2、工作窃取算法 工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。工作窃取的运行流程图如下: ...

JinXYan的博客 364
上一篇: 建造者模式
下一篇: Spring Bean 全生命周期全景图
余生之君
博客等级 码龄10年 246粉丝 98原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值