当前位置: 首页 > news >正文

一文搞懂 java 线程池:ScheduledThreadPool 和 WorkStealingPool 原理

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益:

  1. 了解大厂经验
  2. 拥有和大厂相匹配的技术等

希望看什么,评论或者私信告诉我!

文章目录

  • 一、前言
  • 二、线程池
    • 2.1 ScheduledThreadPool
      • 2.1.1 ScheduledThreadPool 简介
      • 2.1.2 ScheduledThreadPool 常用方法 scheduleAtFixedRate 和 scheduleWithFixedDelay 原理
      • 2.1.3 scheduleAtFixedRate 和 scheduleWithFixedDelay 介绍
    • 2.2 WorkStealingPool
      • 2.2.1 WorkStealingPool 简介
      • 2.2.2 ForkJoinPool 介绍
        • 2.2.2.1 ForkJoinPool 介绍
        • 2.2.2.2 ForkJoinPool 核心-工作窃取算法
        • 2.2.2.2 ForkJoinPool 核心-工作窃取算法优缺点
        • 2.2.2.3 ForkJoinPool 设计
        • 2.2.2.4 ForkJoinPool 完整例子
  • 三、总结


一、前言

上一章节我们详解介绍了SingleThreadExecutorCachedThreadPool 的原理以及应用场景,本章我们继续介绍 ScheduledThreadPoolWorkStealingPool

二、线程池

2.1 ScheduledThreadPool

2.1.1 ScheduledThreadPool 简介

ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后运行任务,或者定期执行任务。

ScheduledThreadPoolExecutor的功能与Timer类似,但ScheduledThreadPoolExecutor功能更强大、更灵活。Timer对应的是单个后台线程,而ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数。
这是它的源码

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());  //调用 ThreadPoolExecutor}

2.1.2 ScheduledThreadPool 常用方法 scheduleAtFixedRate 和 scheduleWithFixedDelay 原理

在这里插入图片描述

DelayQueue是一个无界队列,所以ThreadPoolExecutor的maximumPoolSize在ScheduledThreadPoolExecutor中没有什么意义(设置maximumPoolSize的大小没有什么效果)

  1. 当调用ScheduledThreadPoolExecutor的scheduleAtFixedRate()方法或者scheduleWithFixedDelay()方法时,会向ScheduledThreadPoolExecutor的DelayQueue添加一个实现了RunnableScheduledFutur接口的ScheduledFutureTask。
  2. 线程池中的线程从DelayQueue中获取ScheduledFutureTask,然后执行任务

2.1.3 scheduleAtFixedRate 和 scheduleWithFixedDelay 介绍

scheduleAtFixedRatescheduleWithFixedDelay 都是 ScheduledExecutorService 接口中用于定时执行任务的方法,它们之间的区别在于任务执行的规则:

  1. scheduleAtFixedRate 方法会按照固定的频率执行任务,不考虑任务的实际执行时间。即使前一个任务执行花费的时间超过了频率时间,后续任务也会在规定的频率内执行。例如,如果设定间隔时间为3秒,但任务执行时间为5秒,则任务将按照5秒的间隔执行。
  2. scheduleWithFixedDelay 方法会在前一个任务执行完成后的固定延迟时间后再执行下一个任务。即会等待上一个任务执行完成后才会执行下一个任务。例如,设定延迟时间为3秒,任务执行时间为5秒,则相邻两个任务之间的间隔时间为8秒(5秒执行任务 + 3秒延迟)。

通过选择合适的方法,可以根据实际需求来控制任务的执行规则。scheduleAtFixedRate 更适合需要固定频率执行任务的场景,而 scheduleWithFixedDelay 更适合需要等待前一个任务执行完成后再执行下一个任务的场景。

2.2 WorkStealingPool

2.2.1 WorkStealingPool 简介

WorkStealingPool 是 Java 中的一种线程池实现。WorkStealingPool 是 ForkJoinPool 的一个特例,具有以下特点:

  1. 工作窃取算法:WorkStealingPool 使用工作窃取算法(Work-Stealing Algorithm),每个工作者线程都有一个自己的双端队列用于存储任务,当一个线程的队列为空时,它可以从其他线程的队列中窃取任务来执行,以使工作负载均衡。
  2. 分治任务:WorkStealingPool 使用分治任务的方式来执行任务,可以高效地处理需要递归地分解任务的情况,例如在多核处理器系统中执行并行计算任务。
  3. 并行执行:WorkStealingPool 可以根据需要创建多个工作者线程来并行执行任务,适用于处理需要并行计算或处理的场景。
  4. 自动管理线程数:WorkStealingPool 可以根据需要动态地创建或关闭工作者线程,使得线程数能够根据任务情况和系统资源进行动态调整,提高性能和资源利用率。

由于 WorkStealingPool 使用工作窃取算法和分治任务的方式来执行任务,可以提高并行任务的执行效率和性能。在一些需要处理并行计算、递归分解任务或需要高效利用多核处理器的场景下,WorkStealingPool 是一个很好的选择。

它的源码实现

public static ExecutorService newWorkStealingPool() {return new ForkJoinPool(Runtime.getRuntime().availableProcessors(),ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);
}

2.2.2 ForkJoinPool 介绍

2.2.2.1 ForkJoinPool 介绍

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

Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。

g-blog.csdnimg.cn/img_convert/3e5beb6031a8c6df7ff9093baedf5356.png)

2.2.2.2 ForkJoinPool 核心-工作窃取算法

工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。

假如我们需要做一个比较大的任务,可以把这个任务分割为若干互不依赖的子任务,为了减少线程间的竞争,把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应。比如A线程负责处理A队列里的任务。但是,有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务等待处理。干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。

在这里插入图片描述

2.2.2.2 ForkJoinPool 核心-工作窃取算法优缺点

工作窃取(Work-Stealing)算法是一种用于线程池中任务调度的高效机制。以下是工作窃取算法的一些优点和缺点:

优点:

  1. 负载均衡:

    • 工作窃取算法可以实现任务的动态负载均衡,当某些线程忙碌时,空闲线程可以从其他线程的队列中窃取任务执行,使得整体任务分配更加均衡。
  2. 减少竞争:

    • 不同于传统的线程池中将任务分配给线程执行,工作窃取算法中线程会主动从其他线程的队列中获取任务执行,这减少了线程之间的争夺,降低了同步和竞争的开销。
  3. 提高效率:

    • 工作窃取算法能够更好地利用多核处理器的特性,实现更高效的并发执行,尤其适用于大量计算密集型任务的并行处理。
  4. 适应动态性:

    • 在任务执行过程中,工作窃取算法可以适应动态的负载情况,动态调整任务的分配,以更好地适应不同的任务执行情况。

缺点:

  1. 内存消耗:

    • 由于工作窃取算法需要维护每个线程的工作队列,可能会增加额外的内存消耗,尤其是当线程数量较多时,需要维护多个队列。
  2. 数据局部性降低:

    • 在工作窃取算法中,线程会从其他线程的队列中窃取任务执行,这可能导致数据在不同线程之间频繁传输,降低了数据局部性,影响缓存的效率。
  3. 竞争情况:

    • 尽管工作窃取算法减少了线程之间的竞争,但在真实情况下,仍可能出现一些竞争状况,比如多个线程同时尝试窃取任务时可能会发生竞争。
  4. 复杂性:

    • 实现工作窃取算法需要考虑到线程之间的协调和通信,这增加了算法的复杂性,可能需要更多的编程和调试工作。

尽管工作窃取算法有一些局限性,但在处理大规模并行任务时,它仍然是一种高效的任务调度算法,能够提高并行计算的效率和性能。

2.2.2.3 ForkJoinPool 设计

第一步 分割任务。首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还
是很大,所以还需要不停地分割,直到分割出的子任务足够小。

第二步 执行任务并合并结果。分割的子任务分别放在双端队列里,然后几个启动线程分
别从双端队列里获取任务执行。子任务执行完的结果都统一放在一个队列里,启动一个线程
从队列里拿数据,然后合并这些数据。

Fork/Join使用两个类来完成以上两件事情:

ForkJoinTask:我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务
中执行fork()和join()操作的机制。通常情况下,我们不需要直接继承ForkJoinTask类,只需要继
承它的子类,Fork/Join框架提供了以下两个子类。

  • RecursiveAction:用于没有返回结果的任务。
  • RecursiveTask:用于有返回结果的任务。

ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行。
任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当
一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任

2.2.2.4 ForkJoinPool 完整例子
class FibonacciTask extends RecursiveTask<Integer> {private final int n;public FibonacciTask(int n) {this.n = n;}@Overrideprotected Integer compute() {if (n <= 1) {return n;} else {FibonacciTask task1 = new FibonacciTask(n - 1);FibonacciTask task2 = new FibonacciTask(n - 2);task1.fork(); // 异步执行第一个子任务return task2.compute() + task1.join(); // 执行第二个子任务并等待第一个子任务完成}}
}public class FibonacciMain {public static void main(String[] args) {int n = 10; // 计算斐波那契数列的第n项ForkJoinPool forkJoinPool = new ForkJoinPool();FibonacciTask fibonacciTask = new FibonacciTask(n);int result = forkJoinPool.invoke(fibonacciTask);System.out.println("Fibonacci number at position " + n + " is: " + result);}
}

三、总结

文章重点在于阐述 ScheduledThreadPool 和 WorkStealingPool 的原理及应用。ScheduledThreadPool 适用于定时任务,而 WorkStealingPool 和 ForkJoinPool 适用于并行计算和分治任务,特别是能够充分利用多核 CPU 的计算能力。文章通过代码示例和图解,清晰地解释了这两种线程池的工作机制和优势

相关文章:

一文搞懂 java 线程池:ScheduledThreadPool 和 WorkStealingPool 原理

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…...

轮换IP是什么?——深入了解轮换IP的特点

大家在日常上网时&#xff0c;可能听说过“轮换IP”这个词。那么&#xff0c;轮换IP到底是什么&#xff1f;它有哪些特点&#xff1f;今天&#xff0c;我们就来揭开轮换IP的神秘面纱。 什么是轮换IP&#xff1f; 简单来说&#xff0c;轮换IP是指定期更换上网时使用的IP地址。…...

中英双语介绍美国的州:华盛顿州(Washington)

中文版 华盛顿州简介 华盛顿州&#xff08;Washington&#xff09;位于美国太平洋西北地区&#xff0c;以其壮丽的自然景观和蓬勃发展的经济闻名。以下是对华盛顿州的详细介绍&#xff0c;包括其地理位置、人口、经济、教育、文化和主要城市。 地理位置 华盛顿州北接加拿大…...

美工画师必看!AI绘画Stable Diffusion 一键生成 B 端图标教程,轻松制作商业可用的设计图标,从此告别加班!(附安装包)

大家好&#xff0c;我是画画的小强 在日常工作中&#xff0c;设计师在应对运营和UI设计的B端图标时&#xff0c;常常面临大量的构思、制作和渲染等工作&#xff0c;耗时耗力。我们可以利用Stable Diffusion(以下简称SD)结合AI的方式&#xff0c;帮助设计师优化图标的设计流程&…...

使用表单系统快速搭建邀请和签到系统

在组织活动时&#xff0c;邀请和签到环节往往是活动成败的关键之一。传统的纸质邀请和签到方式不仅费时费力&#xff0c;还容易出现各种问题&#xff0c;例如名单遗漏、签到混乱等。而使用TDuckX“搭建邀请和签到系统”将彻底改变这一现状&#xff0c;为活动组织者提供了一种高…...

Vue 3 入门与精通:为初学者打造的全面学习指南

引言&#xff1a; Vue.js&#xff0c;这款由尤雨溪创建的轻量级前端框架&#xff0c;以其简洁的API、双向数据绑定和组件化的开发模式&#xff0c;深受广大开发者喜爱。Vue 3 的发布&#xff0c;带来了更多的性能优化和功能增强&#xff0c;为开发者提供了更广阔的空间。本文旨…...

React+TS前台项目实战(二十四)-- 全局常用绘制组件Qrcode封装

文章目录 前言Qrcode组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示(pc端 / 移动端) 总结 前言 今天要封装的Qrcode 组件&#xff0c;是通过传入的信息&#xff0c;绘制在二维码上&#xff0c;可用于很多场景&#xff0c;如区块链项目中的区块显示交易地址时就可以用到…...

寄5公斤哪个快递便宜?寄10多斤的物品怎么寄最划算?

作为一个频繁需要寄东西的大学生&#xff0c;每次选择快递公司都是一件头疼的事。尤其是寄5公斤左右的包裹&#xff0c;既要考虑价格&#xff0c;又要看服务质量。今天&#xff0c;我就来分享一些寄5公斤包裹省钱的干货&#xff0c;希望能帮到大家。云木寄快递首先要推荐的就是…...

【postgresql】索引

见的索引类型&#xff1a; B-tree 索引&#xff1a;这是最常用的索引类型&#xff0c;适用于大多数查询。B-tree索引可以高效地处理范围查询。 Hash 索引&#xff1a;适用于等值查询&#xff0c;但不支持范围查询。 GiST 索引&#xff1a;通用搜索树&#xff08;GiST&#xf…...

2D Game Kit在unity的使用

本文参考&#xff1a; 如何制作游戏&#xff1f;【不需要编程 __】新手30分钟 学会制作2D游戏&#xff01;_ 如何制作游戏 _ unity教学 _ 制作游戏 _ 2d游戏_哔哩哔哩_bilibili 1、下载2d game kit 新建一个unity工程&#xff0c;进入该工程后&#xff0c;在Window -> Ass…...

使用中国大陆镜像源安装最新版的 docker Deamon

在一个智算项目交付过程中&#xff0c;出现了新建集群中的全部 docker server V19 进程消失、仅剩 docker server 的 unix-socket 存活的现象。 为了验证是否是BD产品研发提供的产品deploy语句缺陷&#xff0c;需要在本地环境上部署一个简单的 docker Deamon 环境。尴尬的是&a…...

机器学习原理之 -- 支持向量机分类:由来及原理详解

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是统计学习理论的一个重要成果&#xff0c;广泛应用于分类和回归问题。SVM以其高效的分类性能和良好的泛化能力在机器学习领域中占据重要地位。本文将详细介绍支持向量机的由来、基本原理、构建过程及其优缺点。…...

华为机试HJ8合并表记录

华为机试HJ8合并表记录 题目&#xff1a; 数据表记录包含表索引index和数值value&#xff08;int范围的正整数&#xff09;&#xff0c;请对表索引相同的记录进行合并&#xff0c;即将相同索引的数值进行求和运算&#xff0c;输出按照index值升序进行输出。 想法&#xff1a…...

Leetcode 2043简易银行交易系统

题目描述 简易银行系统 尝试过 中等 相关标签 相关企业 提示 你的任务是为一个很受欢迎的银行设计一款程序&#xff0c;以自动化执行所有传入的交易&#xff08;转账&#xff0c;存款和取款&#xff09;。银行共有 n 个账户&#xff0c;编号从 1 到 n 。每个账号的初始余额存储…...

适合职场小白的待办事项管理方法和工具

刚入职场那会儿&#xff0c;我每天都像只无头苍蝇&#xff0c;忙得团团转却效率低下。待办事项像潮水般涌来&#xff0c;会议、报告、客户跟进……每一项都像是悬在头顶的利剑&#xff0c;让我焦虑不堪。我深知&#xff0c;管理好待办事项是职场生存的必修课&#xff0c;但该如…...

相机参数与图像处理技术解析

01. 相机内参和外参的含义&#xff1f;如果将图像放大两倍&#xff0c;内外参如何变化&#xff1f; 相机有两个最基础的数据&#xff1a;内参(Instrinsics)和外参(Extrinsics)&#xff0c;内参主要描述的是相机的CCD/CMOS感光片尺寸/分辨率以及光学镜头的系数&#xff0c;外参主…...

Ubuntu20.04安装Prometheus监控系统

环境准备&#xff1a; 服务器名称内网IP公网IPPrometheus服务器192.168.0.23047.119.21.167Grafana服务器192.168.0.23147.119.22.8被监控服务器192.168.0.23247.119.22.82 更改主机名方便辨认 hostnamectl set-hostname prometheus hostnamectl set-hostname grafana hostn…...

kafka consumer客户端消费逻辑解析

kafka consumer客户端消费逻辑解析 一、主要步骤二、提交策略【步骤2代码解析】【提交策略总结】 三、拉取策略四、消费策略【代码解析】【消费策略总结】 一、主要步骤 这是kafka客户端拉取消息的入口&#xff0c;有4个主要部分 1、启动后的准备 consumer线程启动后&#xff…...

打印机出现多个副本无法删除

打印机出现多个副本很烦人&#xff0c;尤其是在打印机在局域网内被多个主机共享的时候&#xff0c;一旦出现新的副本&#xff0c;原有副本全都变成脱机状态&#xff0c;其他电脑连接的共享打印机是原来的副本&#xff0c;所以要重新设置打印机共享&#xff0c;很烦人。 想要删…...

FlinkSQL 开发经验分享

作者&#xff1a;汤包 最近做了几个实时数据开发需求&#xff0c;也不可避免地在使用 Flink 的过程中遇到了一些问题&#xff0c;比如数据倾斜导致的反压、interval join、开窗导致的水位线失效等问题&#xff0c;通过思考并解决这些问题&#xff0c;加深了我对 Flink 原理与机…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...