任务类型

CPU密集型任务

也叫计算密集型任务,比如加密、解密、压缩、计算等一系列需要大量耗费 CPU 资源的任务。对于这样的任务最佳的线程数为 CPU 核心数的 1~2 倍。

IO密集型任务

比如数据库、文件的读写,网络通信等任务,这种任务的特点是并不会特别消耗 CPU 资源,但是 IO 操作很耗时,总体会占用比较多的时间。对于这种任务最大线程数一般会大于 CPU 核心数很多倍,因为 IO 读写速度相比于 CPU 的速度而言是比较慢的。

推荐的线程计算方法: 线程数 = CPU 核心数 *(1+平均等待时间/平均工作时间)

分治算法

分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。
分治算法的步骤:

  • 分解:将要解决的问题划分成若干规模较小的同类问题
  • 求解:当子问题划分得足够小时,用较简单的方法解决
  • 合并:按原问题的要求,将子问题的解逐层合并构成原问题的解

Fork/Join介绍

是一种基于分治算法的,主要包含两部分,一部分是分治任务的线程池 ForkJoinPool,另一部分是分治任务 ForkJoinTask。ForkJoinPool允许其他线程向它提交任务,并根据设定将这些任务拆分为粒度更细的子任务,这些子任务将由ForkJoinPool内部的工作线程来并行执行,并且工作线程之间可以窃取彼此之间的任务。
ForkJoinPool最适合计算密集型任务,而且最好是非阻塞任务。ForkJoinPool是ThreadPoolExecutor线程池的一种补充,是对计算密集型场景的加强。

ForkJoinPool

ForkJoinPool 是用于执行 ForkJoinTask 任务的执行池,不再是传统执行池 Worker+Queue 的组合式,而是维护了一个队列数组 WorkQueue(数组)

  1. //parallelism指定并行级别,ForkJoinPool将根据这个设定,决定工作线程的数量
  2. //默认是用CPU逻辑和核数来设置并行级别
  3. //factory:ForkJoinPool在创建线程时,会通过factory来创建
  4. // handler:指定异常处理器
  5. //asyncMode:设置队列的工作模式,asyncMode为true时,使用先进先出队列
  6. //asyncMode为false时则使用后进先出的模式
  7. public ForkJoinPool(int parallelism,
  8. ForkJoinWorkerThreadFactory factory,
  9. UncaughtExceptionHandler handler,
  10. boolean asyncMode) {
  11. this(checkParallelism(parallelism),
  12. checkFactory(factory),
  13. handler,
  14. asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
  15. "ForkJoinPool-" + nextPoolId() + "-worker-");
  16. checkPermission();
  17. }

ForkJoinPool提交任务方式

提交异步执行execute

  • execute类型的方法在提交任务后,不会返回结果。可以提交ForkJoinTask任务或者Runnable任务

截屏2022-04-04 23.01.06.png

等待并获取结果invoke

  • invoke方法接受ForkJoinTask类型的任务,并在任务执行结束后,返回泛型结果

提交执行获取Future结果(submit)

  • 在提交任务后,将返回ForkJoinTask类型的结果

截屏2022-04-04 23.04.29.png