并发编程从零开始(十六)-ForkJoinPool

ForkJoinPool是Java并发编程框架中的一个重要组件,尤其适用于分治算法。与ThreadPoolExecutor相比,ForkJoinPool能更有效地实现负载均衡。本文深入探讨了ForkJoinPool的工作原理,包括ForkJoinPool的用法、核心数据结构、工作窃取队列的实现以及Worker线程的阻塞-唤醒机制。通过实例展示了如何利用ForkJoinPool进行快速排序和求和任务,同时解析了ctl变量在控制线程状态中的作用。
摘要由CSDN通过智能技术生成

并发编程从零开始(十六)-ForkJoinPool

第四部分:ForkJoinPool

15 ForkJoinPool用法

ForkJoinPool就是JDK7提供的一种“分治算法”的多线程并行计算框架。Fork意为分叉,Join意为合并,一分一合,相互配合,形成分治算法。此外,也可以将ForkJoinPool看作一个单机版的Map/Reduce,多个线程并行计算。

相比于ThreadPoolExecutor,ForkJoinPool可以更好地实现计算的负载均衡,提高资源利用率。

假设有5个任务,在ThreadPoolExecutor中有5个线程并行执行,其中一个任务的计算量很大,其余4个任务的计算量很小,这会导致1个线程很忙,其他4个线程则处于空闲状态。

利用ForkJoinPool,可以把大的任务拆分成很多小任务,然后这些小任务被所有的线程执行,从而实现任务计算的负载均衡。

例子1:快排

快排有2个步骤:

  1. 利用数组的第1个元素把数组划分成两半,左边数组里面的元素小于或等于该元素,右边数组里面的元素比该元素大;

  2. 对左右的两个子数组分别排序。

左右两个子数组相互独立可以并行计算。利用ForkJoinPool:

image-20211103093250826

image-20211103093311931

例子2:求1到n个数的和

image-20211103093352427

上面的代码用到了 RecursiveAction 和 RecursiveTask 两个类,它们都继承自抽象类ForkJoinTask,用到了其中关键的接口 fork()、join()。二者的区别是一个有返回值,一个没有返回值。

RecursiveAction/RecursiveTask类继承关系:

image-20211103093417372

在ForkJoinPool中,对应的接口如下:

image-20211103093431416


16 核心数据结构

与ThreadPoolExector不同的是,除一个全局的任务队列之外,每个线程还有一个自己的局部队列。

image-20211103093604844

核心数据结构如下所示:

image-20211103093618170

下面看一下这些核心数据结构的构造过程:

image-20211103093637628

image-20211103093653252


17 工作窃取队列

关于上面的全局队列,有一个关键点需要说明:它并非使用BlockingQueue,而是基于一个普通的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值