和阿里P8大佬面试互怼了半小时的Fork/Join的原理!

2024-03-25 15:50

本文主要是介绍和阿里P8大佬面试互怼了半小时的Fork/Join的原理!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

只听到P8大佬不急不慢问道:谈谈对JDK并发工具的认识?

我开始仔细梳理多年的并发八股文积累的经验,道:
线程池、Future、CompletableFuture和CompletionService这些并发工具都帮助SE站在任务角度解决并发问题,而非纠结于线程之间协作的细节,比如线程之间如何实现等待、通知。

  • 简单并行任务
    线程池+Future 组合拳解决
  • 任务之间有聚合关系
    AND、OR聚合,都可以CompletableFuture一招鲜解决
  • 批量的并行任务
    CompletionService一把梭方案

并发编程可分为三个层面问题

  • 分工
  • 协作
  • 互斥

当关注于任务时,你会发现你的视角已脱离于并发编程细节,而使用现实世界思维模式,类比现实世界的分工,其实线程池、Future、CompletableFuture和CompletionService都可列为分工问题。

  • 简单并行任务聚合任务批量并行任务的现实的工作流程图

    这三种任务模型,基本覆盖日常工作中的并发场景,但肯定不全面,还有一种“分治”任务模型。

分治,分而治之,一种解决复杂问题的思维方法和模式。把一个复杂问题分解成多个相似的子问题,然后再把子问题分解成更小的子问题,直到子问题简单到可以直接求解。理论上解决每一个问题都对应着一个任务,所以对于问题的分治,实际上就是对于任务的分治。

P8 大佬直接开问,那你说说什么是分治任务模型?
分治任务模型可分为两个阶段:

  1. 任务分解
    将任务迭代地分解为子任务,直至子任务可计算出结果
  2. 结果合并
    逐层合并子任务的执行结果,直至获得最终结果

就像官僚制度一样:

那你平时开发是如何使用Fork/Join的?

还好这道题,我面试前也准备了…

Fork/Join是一个并行计算框架,以支持分治任务模型

  • Fork对应分治任务模型里的任务分解
  • Join对应结果合并

Fork/Join计算框架主要包含两部分:

  • 分治任务的线程池ForkJoinPool
  • 分治任务ForkJoinTask

这俩的关系类似于 ThreadPoolExecutorRunnable,都是提交任务到线程池,只不过分治任务有自己独特的任务类型ForkJoinTask。

ForkJoinTask

JDK7 提供,一个抽象类,核心方法如下:

  • fork()
    异步执行一个子任务
  • join()
    阻塞当前线程来等待子任务的执行结果

ForkJoinTask有两个子类——RecursiveAction和RecursiveTask,显然都是用递归处理分治任务。这两个子类都定义了抽象方法compute():

  • RecursiveAction#compute()无返回值

  • RecursiveTask#compute()有返回值

    注意到这俩类都是抽象类,使用要定义子类实现。


只见 P8 开始冷笑,看来要问源码级别原理了!

那你说下Fork/Join的工作原理

还好我知道阿里面试套路,凡是 java 工具,必问深入的源码。

因为Fork/Join的核心就是ForkJoinPool,让我来深入讲解ForkJoinPool原理。

ThreadPoolExecutor本质是个生产者-消费者实现,内部有一个任务队列,作为生产者和消费者的通信媒介。ThreadPoolExecutor可以有多个工作线程,这些工作线程都共享一个任务队列。

ForkJoinPool本质上也是一个生产者-消费者的实现,但更智能

  • ForkJoinPool工作原理图

ThreadPoolExecutor内部只有一个任务队列,而ForkJoinPool内部有多个任务队列,当调用ForkJoinPool#invoke()submit()提交任务时,ForkJoinPool把任务通过路由规则提交到一个任务队列,如果任务在执行过程中会创建出子任务,那么子任务会提交到工作线程对应的任务队列。

如果工作线程对应的任务队列空,是不是就没活儿干了?
No!ForkJoinPool有个“任务窃取”机制,若工作线程空闲了,它会“窃取”其他工作任务队列里的任务,例如刚才那个图中,线程T2对应任务队列已空

那它会“窃取”线程T1对应的任务队列的任务。这样所有工作线程都不会闲着。

ForkJoinPool的任务队列采用的是双端队列,工作线程正常获取任务和“窃取任务”分别从任务队列不同的端消费,这也能避免很多不必要的数据竞争。

ForkJoinPool支持任务窃取机制,能够让所有线程的工作量基本公平,不会出现线程有的很忙,有的一直在摸鱼,所以性能很好,是个很公正的领导。
Java8的Stream API里面并行流也是基于ForkJoinPool。
默认,所有的并行流计算都共享一个ForkJoinPool,这个共享的ForkJoinPool的默认线程数是CPU核数;
若所有并行流计算都是CPU密集型,完全没有问题,但若存在I/O密集型并行流计算,那很可能因为一个很慢的I/O计算而拖慢整个系统的性能。所以建议用不同ForkJoinPool执行不同类型的计算任务。

参考

  • https://www.liaoxuefeng.com/article/1146802219354112

这篇关于和阿里P8大佬面试互怼了半小时的Fork/Join的原理!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/845485

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

java程序远程debug原理与配置全过程

《java程序远程debug原理与配置全过程》文章介绍了Java远程调试的JPDA体系,包含JVMTI监控JVM、JDWP传输调试命令、JDI提供调试接口,通过-Xdebug、-Xrunjdwp参数配... 目录背景组成模块间联系IBM对三个模块的详细介绍编程使用总结背景日常工作中,每个程序员都会遇到bu

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数