线程池概述

Java线程池概述及底层原理 线程池的主要作用是通过一个固定数量的线程来执行大量的任务,避免了频繁地创建和销毁线程的开销。线程池采用了生产者-消费者的模型,任务提交者(生产者)提交任务给线程池,线程池中的线程(消费者)取出任务执行。减少资源消耗:避免频繁创建和销毁线程,提高资源利用率。提高响应速度:避免了线程的创建和销毁时间,任务可以直接交给空闲线程执行。更好的资源管理:线程池可以控制线程的最大并发数,防止资源耗尽。线程复用:线程池中的线程可以被复用,减少了创建线程的开销。通过类,开发者可以自定义线程池的配置,满足特定的业务需求。 阅读详情

线程池

池的意义

在资源不足以满足当前需求时,将资源圈定为池,反复利用(计划经济),从而满足当前需求,从本质上来讲是一种以时间换空间的做法。

线程池的意义

线程池,是在存在大量任务的前提下,固定一定数量的线程去执行这些任务;提高了线程本身的利用率,减少了大量创建销毁线程所带来的性能开销问题。、

线程池解决的问题

  • 反复创建线程开销大 -> 线程池只创建少量线程并反复利用去执行任务、
  • 过多的线程会占用较大的进程内存 -> 线程池同时存货的线程只有少量

线程池的好处

  • 合理利用资源(CPU和内存)
  • 统一管理资源
  • 加快程序的响应速度(减少线程创建 -> 减少资源开销 -> 加快程序执行速度)

线程池的创建和停止

线程池的创建

构造函数参数
  • corePoolSize:核心线程数,默认情况下,线程池中存活的最少线程数量,但是如果allowCoreThreadTimeout设置为true,那么核心线程在空闲时也会被回收
  • maxPoolSize:最大线程数,在核心线程和任务存储队列都工作饱和的情况下,线程池会再创建线程,此时线程池中线程上限为最大线程数;workQueue非无界队列时该参数才有意义
  • keepAliveTime:非核心空闲线程的保持存活时间,目的是回收空闲的非核心线程,保持线程池的线程数量,减少线程池资源消耗
  • workQueue:任务存储队列,如果核心线程都在执行任务,那么会先把任务放入workQueue中,等待线程池线程来执行
  • threadFactory:线程创建的工厂,默认工厂Executors.defaultThreadFactory创建出的线程都在同一个线程组,有同样的优先级且都不是守护线程
  • handler:线程拒绝策略,当线程池已经关闭,或核心线程、非核心线程和工作队列都已满时,对新提交的工作任务执行的拒绝策略
线程池创建方法的选择
  • 手动创建:在明确业务场景的情况下最好是手动创建线程池,可以让我们更明确当前线程池的运行规则,避免资源耗尽等风险
  • 自动创建:方便,但是有各自的危害
    • FixedThreadPool:core = max,但是workQueue是LinkedBlockingQueue,那么在线程处理速度赶不上任务提交速度时,极有可能OOM
    • SingleThreaPool:core = max = 1,workQueue为LinkedBlockingQueue,和Fix一样,可能OOM
    • CachedThreadPool:该线程池和上述两个线程池不同,它的主要风险点在于maxPoolSize,该参数被设置为Integer.MAX_VALUE,且因为workQueue为SynchronousQueue,只中转任务,最后会导致线程一直被创建,最终OOM
    • SheduleThreadPool:该线程池的主要问题在于参数workQueue,它的容量只有16,但是以150%的比率进行resize,上限为Integer.MAX_VALUE,如果被不断提交一些执行时间/周期较长的任务,在线程数量或队列容量方面都有可能导致OOM,且workQueue导致maxPoolSize无意义

线程添加规则

  • 如果线程数小于corePoolSize,那么在新任务的情况下,即使存在空闲线程,也会创建新线程来执行任务
  • 如果线程数等于/大于corePoolSize,但是小于maxPoolSize,且任务存储队列未满,那么会将新任务放入任务存储队列中
  • 如果线程数等于/大于corePoolSize,但是小于maxPoolSize,且任务存储队列已满,则创建新线程执行任务
  • 如果线程数等于/大于maxPoolSize,且任务存储队列已满,则对新任务执行线程拒绝策略

线程增减特性

  • coorPoolSize = maxPoolSize,即固定线程数的线程池
  • 线程池希望保持较小的线程数,所以只在必要时(负载变得很大)才增加线程数
  • 通过提高设置maxPoolSize,比如Integer.MAX_VALUE,可以让线程池处理任意数量的并发任务
  • 通过设置workQueue为无界队列,可以让线程池容纳任务数量的任务

常见工作队列

  • SynchronousQueue:直接交接队列,对工作任务只做中转,不存储任务,会阻塞任务提交线程/任务处理线程
  • LinkedBlockingQueue:无界队列,如果线程处理速度小于任务提交速度,会导致队列中任务一直增加,最终造成OOM;该队列让maxPoolSize无效
  • ArrayBlockingQueue:有界队列,可以在生成线程池时提前设置好队列大小,是比较常用的一种工作队列

线程数量的计算

  • CPU密集型任务:比如加密、计算等相关任务,这些任务会频繁的使用CPU,那么此时我们可以直接将线程数量设置为CPU数量的一至两倍,最大程度上利用CPU资源
  • IO密集型任务:比如读写数据库、读取文件、网络读写等相关任务,这些任务会经常在等待某些资源,那么线程数可以设置为CPU的很多倍,保证CPU不会处在等待期间内,具体的一个数量可以通过压测得出

Brain Goetz的计算公式:线程数 = CPU核心数 * (1 + 平均等待时间 / 平均工作时间),平均等待时间代表CPU的等待时间,平均工作时间代表CPU的工作时间,前者越大说明CPU需要等待的时间越长,可以把线程数量设置的大一些,尽量不让CPU空闲;后者越大则说明使用CPU的时间越长,线程数量需要设置的小一些,因为CPU已经满负荷运转了,设置再多的线程也只是徒劳,只会给内存增加压力

线程池关闭的相关方法

  • shutdown:该方法仅仅是初始化整个关闭过程,会将正在执行的任务和队列中的任务执行完,对新任务会执行rejectHandler
  • isShutdown:判断线程池是否被标记为关闭状态
  • isTerminated:判断整个线程池是否已经完全停止了,这里的完全停止意味着正在执行和任务队列中的任务都已完成,线程池已关闭
  • awaitTermination:检测线程池是否完全关闭,会根据传入的时间参数阻塞调用线程
  • shutdownNow:暴力结束线程池,会对正在执行任务的线程调用interrupt(),并以List<Runnable>的形式返回任务队列中的所有任务,但是需要注意,这并不意味着该线程池已经terminated,有些线程还在执行中,因为interrupt()方法不会立刻停止线程

线程池的拒绝策略

拒绝时机
  • 线程池已经被关闭
  • maxPool和workQueue都已满
拒绝策略
  • AbortPolicy:抛出RejectExecutionException,相当于一个通知去告知任务提交方,线程池不执行这个任务
  • DiscardPolicy:默默丢弃任务,不通知任务提交方
  • DiscardOldestPolicy:抛弃工作队列中最老的任务(一般为队列头),把新提交的任务加入工作队列中
  • CallerRunsPolicy:让任务提交方去执行当前任务

线程池的钩子

钩子,即任务执行前后进行的一些操作,相当于给线程池加了个切面,这是ThreadPoolExecutor中提供的一些方法,可以通过重写去定义相关操作

  • beforeExecution
  • afterExecution

线程池的组成部分

线程池主要由以下四部分组成

  • 线程池管理器
  • 工作线程
  • 工作队列
  • 任务接口

线程池中线程的复用

线程池的线程,比如corePool中的线程,都是已经被调用过start(),这些线程的作用(run())是,不断的去任务队列中获取任务,然后直接调用任务的run(),让任务执行

线程池的状态

  • RUNNING:接受新任务并执行
  • SHUTDOWN:不接受新任务,但是会将线程正在执行的和任务队列中的任务执行完,调用shutdown()后线程池会处在该状态
  • STOP:不接受新任务,泛起并返回工作队列中所有未执行任务,并调用正在执行任务的线程的interrupt()方法,调用shutdownNow()后线程池会处在该状态
  • TIDYING:任务队列为空,工作线程数为0,该状态后线程池就会调用terminated()方法真正终止线程池
  • TERMINATED:terminated()方法运行完成后,线程池转变到该状态

使用线程池的注意点

  • 避免任务堆积
  • 避免线程数过度增加
  • 避免线程泄露,即因为任务逻辑或某些异常原因,导致线程池中的线程数量和预期的不符
【用unity实现100个游戏之7】实现一个类《杀戮尖塔》的卡牌回合制游戏(附项目源码) 阅读详情

相关推荐

如何从RHEL 8升级到RHEL 9

Red Hat 于 2022 年 5 月 17 日宣布全面推出 RHEL 9。这是 RHEL(Red Hat Enterprise Linux)的最新版本,它具有许多功能和增强功能。

u012748257的博客 1019

线程池研发学习笔记

可以直接叙述,也可以对比连接池介绍```线程池其实就是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务。这里的线程就是我们前面学过的线程,这里的任务就是我们前面学过的实现了Runnable或Callable接口的实例对象;```1:网购商品秒杀多人同时抢购某件商品,只有部分人会成功,其他人失败;2:云盘文件上传和下载同时可以上传多个文件或下载多个文件,且有最大上传和下载文件的个数限制;3:12306网上购票系统等。

liuhm的博客 2022

从零到一:用Verilog和Quartus构建智能交通灯系统的实战指南

本文详细介绍了如何使用Verilog和Quartus Prime从零开始构建智能交通灯系统。通过分步指导,包括状态机设计、时序控制、数码管显示等核心模块实现,并结合ModelSim仿真验证,帮助FPGA初学者掌握数字电路设计的关键技术。文章还提供了实际部署到FPGA开发板的调试技巧和进阶优化方案。

weixin_29172201的博客 474

写给大忙人看的如何优雅设置线程池的大小

假如线程池的大小设置过大,线程上线文切换过于频繁,造成大量资源开销,反而会使性能降低;假如设置的太小,存在很多可用的处理器资源却未在工作,会造成资源的浪费和对吞吐量造成损失。如何优雅的设置线程池的大小呢?

万猫学社 1万+

Halcon实战:5分钟搞定工业零件中的圆孔检测(附完整代码)

本文详细解析了如何利用Halcon的hough_circle算法在5分钟内高效完成工业零件中的圆孔检测。通过优化图像采集、智能预处理和参数化边缘检测,解决了金属反光、油污干扰等工业场景常见问题,并提供了完整的代码示例和实战案例,显著提升检测精度和效率。

weixin_29061997的博客 239

R语言实战:GEO单细胞数据下载与自动化整理全流程(附代码)

本文详细介绍了使用R语言从GEO数据库下载scRNA-seq数据并实现自动化整理的完整流程。通过GEOquery和Seurat等工具包,读者可以高效获取单细胞RNA测序数据,完成从原始数据下载到预处理的全过程,最终生成可直接用于分析的Seurat对象。文章包含完整代码示例,特别适合生物信息学研究者处理单细胞数据。

weixin_29061821的博客 427

线程池总体概述

线程池主要是为了线程的复用,减少线程频繁创建和销毁的开销。ThreadPoolExecutor便是“线程池”,其继承结构如下: 顶层接口Executor,只定义了一个执行任务的方法: void execute(Runnable command); ExecutorService则对Executor进行了拓展,增加了shutdown,submit等方法: 而AbstractExecutorService则是对ExecutorService进行了默认实现,主要还是看ThreadPoolExec

qiuxinfa123的博客 189

CANoe如何实现TLS协议

TLS,Transport Layer Security,传输层安全协议。是在传输层和应用层之间,为了保证应用层数据能够安全可靠地通过传输层传输且不会泄露的安全防护。

jasonj333 1159

关于线程池的概述

A:线程池概述 程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池。 B:内置线程池的使用概述 JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法: public static Executo

pipizhen_的博客 295

[Dify实战] OA 公文排版助手:自动格式化、编号、生成摘要-带配套资源

摘要: Dify 公文排版助手通过自动化解决公文处理中的格式混乱、编号错漏等问题。支持标题层级自动编号、摘要生成、要素补全等功能,输出标准化Markdown格式。核心流程包括输入原文、智能识别、自动排版与要素输出,适用于通知、纪要等场景。实施需统一模板规则,规范输入格式,并通过试跑优化纠错率与处理效率。关键价值在于减少人工返工,提升排版一致性,未来可对接OA系统实现全流程自动化。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 472

YOLOv8【第二十六章:游戏与娱乐产业 YOLO 应用篇·第14节】游戏性能压测:YOLO 在高帧率引擎下的优化指南!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》 专栏。该专栏系统复现并梳理全网各类 YOLOv8 改进与实战案例(当前已覆盖分类 / 检测 / 分割 / 追踪 / 关键点 / OBB 检测等方向),坚持持续更新 + 深度解析,质量分长期稳定在 97 分以上,可视为当前市面上 覆盖较全、更新较快、实战导向极强 的 YOLO 改进系列内容之一。

**My Coding Family** 324

线程池的概述

线程池的概述 一 、基础概述 1.什么是线程池 ​ 线程池就是提前创建若干个线程,如果有任务需要处理,线程池里的线程就会处理任务,处理完之后线程并不会被销毁,而是等待下一个任务。由于创建和销毁线程都是消耗系统资源的,所以当你想要频繁的创建和销毁线程的时候就可以考虑使用线程池来提升系统的性能。 2.使用线程池的好处 减少创建线程、销毁线程所花的时间,以及避免系统资源浪费 可以重复利用线程,避免...

算云烟 261

【PCIe 总线及设备入门学习专栏 1.3 -- PCIe 基础知识 lane和link介绍】

PCIe RC(Root Complex)是PCIe树的根节点,一个RC 可以包括多个 RP(Root Port),例如一个16 条 lane的PCIe RC 可以包括4个RP(4个x4的),或者8个RP(8个x2的)等等。在该模式下,数据传送由CPU执行I/O端口指令来按照字节或更大的数据单位来处理,占用大量的CPU资源,数据传输速度也大大低于DMA模式。国内应该有公司做出相应的phy芯片(例如芯动科技、牛芯半导体),毕竟常见的pcie 3.0才8 Gbps的速率,最新的6.0才64Gbps。

CodingCos的博客 2104

java线程池概述

java线程池概述 创建线程,有两种方式: 继承Thread 实现Running接口 日常使用的使用看这两种创建方式差别不大,实际上稍微有点区别:主要在于多线程访问同一资源的情况下,Running方式创建的线程可以操作同一共享资源,继承Thread方式创建的线程是独立各自有自己的资源,互不干扰(当然我们可以给Thread类中通过各种方式传递参数等)。 只有一个两个线程时手动创建也没什么问题,但是在高并发的情况下,大量创建线程是有致命缺陷的: 1、线程的创建和销毁是需要一定时间的,大量创建销毁线程的时候

dream_caoyun的博客 301

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

线程池基本概述

1

weixin_40487115的博客 175

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

线程池核心概述

线程池核心概述 Executors工厂类使用 Executors工厂类底层源码分析详解 ThreadPoolExecutor自定义线程池 ThreadPoolExecutor拒绝策略详解 计算机密集型与IO密集型详解 如...

CHYabc123456hh的博客 244

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【c++】【线程池】线程池概述

线程池(Thread Pool)是一种多线程编程的技术,它的核心思想是并将它们组织起来管理。当任务到达时,线程池可以直接来处理,而无需每次都创建新线程。线程池能够显著,并能够有效地。线程池的基本结构:1.任务队列(TaskQueue):用于存放。通常是一个线程安全的队列。2.工作线程:线程池中的线程,负责从任务队列中取出任务并执行。3.线程池管理:负责创建、管理和销毁工作线程。它还负责任务的调度和队列的管理。

m0_64014551的博客 1062

线程池的概述和使用

线程池的概述和使用 A:线程池概述 程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池。 ...

LeoZuosj的博客 232

Java ThreadPoolExecutor线程池概述

导航 前言 为什么要使用线程池 线程池使用方式 Executors创建线程池 newCachedThreadPool newFixedTh...

starbxx的博客 241
上一篇: 关于MyBatis重复指定Mapper报错
下一篇: 线程池ThreadPoolExecutor源码详解 --- 更新中
XIACYBING
博客等级 码龄10年 1粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值