JVM中的线程池详解:原理→实践
一、为什么需要线程池?
在多线程编程中,频繁地创建和销毁线程会带来显著的性能开销。
想象一下,如果你经营一家西餐厅,每次有顾客到来你都雇佣新的服务员,顾客吃完结账后就解雇——这种模式是不是非常效率低下且成本高昂啊,并且还可能会被人说成是傻子。
线程池就像一支固定下来的服务员团队,能高效复用线程资源。
线程池的核心优势:
降低资源消耗:复用已创建的线程,避免频繁创建销毁
提高响应速度:任务到达时可直接使用空闲线程
增强可管理性:统一监控和调优线程使用情况
防止资源耗尽:通过队列机制控制并发数量
二、JVM内存模型与线程池的关系

1. 线程私有区域
程序计数器:每个线程独立记录执行位置
虚拟机栈:存储线程方法调用的栈帧
本地方法栈:Native方法调用使用
2. 线程共享区域
堆:存放所有线程池中的任务对象
方法区:存储线程池类的元数据信息
直接内存:NIO操作可能使用的非堆内存
关键:线程池中的每个工作线程都拥有独立的虚拟机栈和程序计数器,而任务对象和线程池本身存储在堆中。既能保证线程安全,又可以实现资源共享。
三、Java线程池核心实现
1. ThreadPoolExecutor 核心参数
public ThreadPoolExecutor(int corePoolSize, // 核心线程数int maximumPoolSize, // 最大线程数long keepAliveTime, // 空闲线程存活时间TimeUnit unit, // 时间单位BlockingQueue<Runnable> workQueue, // 任务队列RejectedExecutionHandler handler // 拒绝策略
)
2. 工作流程详解

提交任务时优先使用核心线程
核心线程忙时任务进入队列
队列满时创建非核心线程
达到最大线程数后触发拒绝策略
3. 四种拒绝策略对比
| 策略类 | 处理方式 | 适用场景 |
|---|---|---|
| AbortPolicy | 直接抛出RejectedExecutionException | 严格要求任务不丢失 |
| CallerRunsPolicy | 由提交任务的线程执行任务 | 需要降级处理 |
| DiscardPolicy | 静默丢弃新任务 | 允许丢失部分任务 |
| DiscardOldestPolicy | 丢弃队列最旧任务并重试 | 优先处理新任务 |
四、线程池与JVM内存管理
1. 内存消耗分析
-
每个线程消耗:约1MB栈内存(默认-Xss1M)
-
典型问题场景:
// 危险示例:可能导致OOM Executors.newCachedThreadPool(); // 最大线程数=Integer.MAX_VALUE
2. 推荐创建方式
// 安全的手动创建方式
new ThreadPoolExecutor(5, // 核心线程数10, // 最大线程数60L, TimeUnit.SECONDS,new ArrayBlockingQueue<>(100), // 有界队列new CustomRejectionPolicy()
);
3. 内存优化建议
设置合理的线程上限(通常不超过CPU核心数*2)
使用有界队列避免内存溢出
监控堆内存使用(特别是长期存活的线程对象)
五、线程池监控与调优
1. 关键监控指标
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
System.out.println("活跃线程数: " + pool.getActiveCount());
System.out.println("已完成任务数: " + pool.getCompletedTaskCount());
System.out.println("队列大小: " + pool.getQueue().size());
2. 推荐工具
JConsole:可视化监控线程状态
VisualVM:分析线程堆栈信息
Arthas:实时诊断线上问题
3. 最佳实践
IO密集型任务:建议线程数 = CPU核心数 * (1 + 平均等待时间/计算时间)
CPU密集型任务:线程数 ≈ CPU核心数 + 1
混合型任务:拆分不同线程池处理
六、常见问题排查
1. 线程泄漏
现象:线程数持续增长不释放
排查:
检查是否忘记关闭线程池
分析线程堆栈(jstack命令)
确认任务是否存在无限阻塞
2. 内存溢出
可能原因:
使用无界队列导致任务堆积
任务对象持有大内存引用
线程本地变量未清理
解决方案:
// 使用ScheduledThreadPoolExecutor进行内存监控
ScheduledExecutorService monitor = Executors.newScheduledThreadPool(1);
monitor.scheduleAtFixedRate(() -> {long usedMB = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024;System.out.println("内存使用: " + usedMB + "MB");
}, 0, 30, TimeUnit.SECONDS);
七、线程池生命周期管理
1. 状态流转图

2. 正确关闭方式
executor.shutdown(); // 平缓关闭
if(!executor.awaitTermination(60, TimeUnit.SECONDS)){executor.shutdownNow(); // 强制关闭
}
相关文章:
JVM中的线程池详解:原理→实践
一、为什么需要线程池? 在多线程编程中,频繁地创建和销毁线程会带来显著的性能开销。 想象一下,如果你经营一家西餐厅,每次有顾客到来你都雇佣新的服务员,顾客吃完结账后就解雇——这种模式是不是非常效率低下且成本高…...
SNARKs 和 UTXO链的未来
1. 引言 SNARKs 经常被视为“解决”扩容问题的灵丹妙药。虽然 SNARKs 可以提供令人难以置信的好处,但也需要承认其局限性——SNARKs 无法解决区块链目前面临的现有带宽限制。 本文旨在通过对 SNARKs 对比特币能做什么和不能做什么进行(相对)…...
JavaScript设计模式 -- 外观模式
在实际开发中,往往会遇到多个子系统协同工作时,直接操作各个子系统不仅接口繁琐,还容易导致客户端与内部实现紧密耦合。**外观模式(Facade Pattern)**通过为多个子系统提供一个统一的高层接口,将复杂性隐藏…...
百达翡丽(Patek Philippe):瑞士制表的巅峰之作(中英双语)
百达翡丽(Patek Philippe):瑞士制表的巅峰之作 在钟表界,百达翡丽(Patek Philippe) 一直被誉为“世界三大名表”之一,并且常被认为是其中的至高存在。一句“没人能真正拥有一枚百达翡丽&#x…...
阿里云一键部署DeepSeek-V3、DeepSeek-R1模型
目录 支持的模型列表 模型部署 模型调用 WebUI使用 在线调试 API调用 关于成本 FAQ 点击部署后服务长时间等待 服务部署成功后,调用API返回404 请求太长导致EAS网关超时 部署完成后,如何在EAS的在线调试页面调试 模型部署之后没有“联网搜索…...
分享一款AI绘画图片展示和分享的小程序
🎨奇绘图册 【开源】一款帮AI绘画爱好者维护绘图作品的小程序 查看Demo 反馈 github 文章目录 前言一、奇绘图册是什么?二、项目全景三、预览体验3.1 截图示例3.2 在线体验 四、功能介绍4.1 小程序4.2 服务端 五、安装部署5.1 快速开始~~5.2 手动部…...
【练习】【双指针】力扣热题100 283. 移动零
题目 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0] 输出…...
QT 互斥锁
一、概述 1、在多线程编程中,为了防止多个线程同时访问共享资源而导致的不确定性和错误,经常会使用互斥锁(Mutex)进行保护。 2、QMutex是Qt提供的一个互斥锁类,用于确保在同一时间只有一个线程访问共享资源。 3、QM…...
什么是算法的空间复杂度和时间复杂度,分别怎么衡量。
1. 时间复杂度 时间复杂度衡量的是算法运行时间与输入规模之间的关系。它通常用大O记号(Big O Notation)表示,例如 O(1)、O(n)、O(n2) 等。 衡量方法: 常数时间复杂度 O(1):无论输入规模如何,算法的执行时…...
VMware Workstation 17.0 Pro创建虚拟机并安装Ubuntu22.04与ubuntu20.04(双版本同时存在)《包含小问题总结》
目录 一、创建虚拟机 二、下载安装22.04 三、一些配置问题总结(小屏,网络,复制贴贴等) 1、网络问题 2、sudo apt install net-tools出现无法定为软件包 3、小屏与ubuntu虚拟机与windows系统之间复制粘贴 4、安装终端:Termi…...
Windows 10 ARM工控主板CAN总线实时性能测试
在常规的Windows系统中支持CAN总线应用,需要外接CAN总线适配器,通常为USB转CAN模块或PCI接口CAN卡。实时性本身是CAN总线的显著特性之一,但由于Windows并非实时操作系统,应用程序容易受到系统CPU负载影响,导致调度周期…...
如何在不依赖函数调用功能的情况下结合工具与大型语言模型
当大型语言模型(LLM)原生不支持函数调用功能时,如何实现智能工具调度?本文通过自然语言解析结构化输出控制的方法来实现。 GitHub代码地址 核心实现步骤 定义工具函数 使用tool装饰器声明可调用工具: from langcha…...
【Linux AnolisOS】关于Docker的一系列问题。尤其是拉取东西时的网络问题,镜像源问题。
AnolisOS 8中使用Docker部署(全)_anolis安装docker-CSDN博客 从在虚拟机安装龙蜥到安装docker上面这篇文章写的很清晰了,我重点讲述我解决文章里面问题一些的方法。 问题1: docker: Get https://registry-1.docker.io/v2/: net/h…...
【Elasticsearch】Mapping概述
以下是Elasticsearch中提到的关于Mapping的各模块概述: --- 1.Dynamic mapping(动态映射) 动态映射是指Elasticsearch在索引文档时,自动检测字段类型并创建字段映射的过程。当你首次索引一个文档时,Elasticsearch会根…...
GPT-4o悄然升级:能力与个性双突破,AI竞技场再掀波澜
在大模型竞技场中,GPT-4o悄悄发布了全新版本,凭借其卓越的多项能力,迅速超越了DeepSeek-R1,成功登上并列第一的位置。这次更新不仅在数学(第6名)上有所突破,还在创意写作、编程、指令遵循、长文…...
如何选择合适的超参数来训练Bert和TextCNN模型?
选择合适的超参数来训练Bert和TextCNN模型是一个复杂但关键的过程,它会显著影响模型的性能。以下是一些常见的超参数以及选择它们的方法: 1. 与数据处理相关的超参数 最大序列长度(max_length) 含义:指输入到Bert模…...
C# SpinLock 类 使用详解
总目录 前言 SpinLock 是 C# 中一种轻量级的自旋锁,属于 System.Threading 命名空间,专为极短时间锁竞争的高性能场景设计。它通过忙等待(自旋)而非阻塞线程来减少上下文切换开销,适用于锁持有时间极短(如…...
【linux】在 Linux 上部署 DeepSeek-r1:32/70b:解决下载中断问题
【linux】在 Linux 上部署 DeepSeek-r1:32/70b:解决下载中断问题 【承接商业广告,如需商业合作请+v17740568442】 文章目录 【linux】在 Linux 上部署 DeepSeek-r1:32/70b:解决下载中断问题问题描述:解决方法方法一:手动中断并重启下载方法二:使用 Bash 脚本自动化下载在…...
机器学习所需要的数学知识【01】
总览 导数 行列式 偏导数 概理论 凸优化-梯度下降 kkt条件...
4.【线性代数】——矩阵的LU分解
四 矩阵的LU分解 1. AB的逆矩阵2. 转置矩阵3. ALU3.1 2x2矩阵3.2 3x3矩阵3.3 nxn的矩阵分解的次数? 1. AB的逆矩阵 { ( A B ) ( B − 1 A − 1 ) I ( B − 1 A − 1 ) ( A B ) I ⇒ ( A B ) − 1 B − 1 A − 1 \begin{cases} (AB)(B^{-1}A^{-1}) I\\ (B^{-1}A^…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
