线程池 坑中之王 !

codemirror6 制作markdown编辑器(源码模式) 总体上感觉能用,但是不怎么友好,官方文档有点散乱,而且关键字高亮功能是独立出去的,去官方文档找半天,也没找到怎么改。EditorView.theme可以往EditorView模块中修改CSS的样式,从而影响编辑器的样式展示。"### 测试\n\n```javascript\nlet x = 'y'\n```"这个插件中的markdown语法的高亮样式。//这里指定markdown中代码块使用的解析扩展。开头的class样式,并且还需要在选择器前面添加。//markdown语言解析扩展。 阅读详情

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 

b2474795a345a5f278a390cd61ee7989.gif

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号、ERP、CRM、AI 大模型等等功能:

  • Boot 多模块架构:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • Cloud 微服务架构:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

【国内首批】支持 JDK 17/21 + SpringBoot 3.3、JDK 8/11 + Spring Boot 2.7 双版本 

来源:苏三说技术

a48c2b53a918871f174ce42e1da6505a.jpeg


前言

线程池是 Java 中处理多线程的强大工具,但它不仅仅是“直接用就完事”的工具。

很多小伙伴在用线程池时,因为配置不当或忽略细节,踩过许多坑。

今天跟大家一起聊聊线程池中容易踩的 10 个坑,以及如何避免这些坑,希望对你会有所帮助。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

1. 直接使用 Executors 创建线程池

许多初学者在创建线程池时,直接使用 Executors 提供的快捷方法:

ExecutorService executor = Executors.newFixedThreadPool(10);
问题在哪?
  • 无界队列 :newFixedThreadPool 使用的队列是 LinkedBlockingQueue,它是无界队列,任务堆积可能会导致内存溢出。

  • 线程无限增长 :newCachedThreadPool 会无限创建线程,在任务量激增时可能耗尽系统资源。

示例:内存溢出的风险
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 1000000; i++) {
    executor.submit(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

任务数远大于线程数,导致任务无限堆积在队列中,最终可能导致 OutOfMemoryError。

解决办法

使用 ThreadPoolExecutor,并明确指定参数:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2,
    4,
    60L,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(100), // 有界队列
    new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

2. 错误配置线程数

很多人随意配置线程池参数,比如核心线程数 10,最大线程数 100,看起来没问题,但这可能导致性能问题或资源浪费。

示例:错误配置导致的线程过载
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    10, // 核心线程数
    100, // 最大线程数
    60L,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(10)
);

for (int i = 0; i < 1000; i++) {
    executor.submit(() -> {
        try {
            Thread.sleep(5000); // 模拟耗时任务
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

这种配置在任务激增时,会创建大量线程,系统资源被耗尽。

正确配置方式

根据任务类型选择合理的线程数:

  • CPU 密集型 :线程数建议设置为 CPU 核心数 + 1。

  • IO 密集型 :线程数建议设置为 2 * CPU 核心数。

示例:

int cpuCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    cpuCores + 1,
    cpuCores + 1,
    60L,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(50)
);

3. 忽略任务队列的选择

任务队列直接影响线程池的行为。如果选错队列类型,会带来很多隐患。

常见队列的坑
  • 无界队列 :任务无限堆积。

  • 有界队列 :队列满了会触发拒绝策略。

  • 优先级队列 :容易导致高优先级任务频繁抢占低优先级任务。

示例:任务堆积导致问题
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2,
    4,
    60L,
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>()
);

for (int i = 0; i < 100000; i++) {
    executor.submit(() -> System.out.println(Thread.currentThread().getName()));
}

改进方法 :用有界队列,避免任务无限堆积。

new ArrayBlockingQueue<>(100);

4. 忘记关闭线程池

有些小伙伴用完线程池后,忘记调用 shutdown(),导致程序无法正常退出。

示例:线程池未关闭
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> System.out.println("任务执行中..."));
// 线程池未关闭,程序一直运行
正确关闭方式
executor.shutdown();
try {
    if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
        executor.shutdownNow();
    }
} catch (InterruptedException e) {
    executor.shutdownNow();
}

5. 忽略拒绝策略

当任务队列满时,线程池会触发拒绝策略,很多人不知道默认策略(AbortPolicy)会直接抛异常。

示例:任务被拒绝
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    1,
    1,
    60L,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(2),
    new ThreadPoolExecutor.AbortPolicy() // 默认策略
);

for (int i = 0; i < 10; i++) {
    executor.submit(() -> System.out.println("任务"));
}

执行到第四个任务时会抛出 RejectedExecutionException。

改进:选择合适的策略
  • CallerRunsPolicy:提交任务的线程自己执行。

  • DiscardPolicy:直接丢弃新任务。

  • DiscardOldestPolicy:丢弃最老的任务。

6. 任务中未处理异常

线程池中的任务抛出异常时,线程池不会直接抛出,导致很多问题被忽略。

示例:异常被忽略
executor.submit(() -> {
    throw new RuntimeException("任务异常");
});
解决方法
  1. 捕获任务内部异常:

executor.submit(() -> {
    try {
        throw new RuntimeException("任务异常");
    } catch (Exception e) {
        System.err.println("捕获异常:" + e.getMessage());
    }
});
  1. 自定义线程工厂:

ThreadFactory factory = r -> {
    Thread t = new Thread(r);
    t.setUncaughtExceptionHandler((thread, e) -> {
        System.err.println("线程异常:" + e.getMessage());
    });
    return t;
};

7. 阻塞任务占用线程池

如果线程池中的任务是阻塞的(如文件读写、网络请求),核心线程会被占满,影响性能。

示例:阻塞任务拖垮线程池
executor.submit(() -> {
    Thread.sleep(10000); // 模拟阻塞任务
});
改进方法
  • 减少任务的阻塞时间。

  • 增加核心线程数。

  • 使用异步非阻塞方式(如 NIO)。

8. 滥用线程池

线程池不是万能的,某些场景直接使用 new Thread() 更简单。

示例:过度使用线程池

一个简单的短期任务:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> System.out.println("执行任务"));
executor.shutdown();

这种情况下,用线程池反而复杂。

改进方式
new Thread(() -> System.out.println("执行任务")).start();

9. 未监控线程池状态

很多人用线程池后,不监控其状态,导致任务堆积、线程耗尽的问题被忽略。

示例:监控线程池状态
System.out.println("核心线程数:" + executor.getCorePoolSize());
System.out.println("队列大小:" + executor.getQueue().size());
System.out.println("已完成任务数:" + executor.getCompletedTaskCount());

结合监控工具(如 JMX、Prometheus),实现实时监控。

10. 动态调整线程池参数

有些人在线程池设计时忽略了参数调整的必要性,导致后期性能优化困难。

示例:动态调整核心线程数
executor.setCorePoolSize(20);
executor.setMaximumPoolSize(50);

实时调整线程池参数,能适应业务的动态变化。

总结

线程池是强大的工具,但如果我们日常工作中用得不好也非常容易踩坑。

这篇文章通过实际代码示例,我们可以清楚看到线程池的问题所在及改进方法。

希望这些内容能帮你避免踩坑,写出高质量的线程池代码!

线程池用得好,效率杠杠的;用得不好,程序天天崩!


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,“长按”或“扫描”下方二维码噢:

5ced84d0238c0865a9959a568c9c277e.png

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

8585ac4fab650bf4088c52107725bba2.png

7da79893013f533b23435b6d3618343b.png8b156f1e2abba63a0951f0132cf45bca.pngffe317a3af33c106e44f70728d98b7b1.png1037ec4757aefed1489e23c462b47de6.png

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
AUTOSAR MCAL开发及EB Tresos工具使用总结 在基于AutoSar CP架构开发MCAL时,会使用到EB tresos工具。本文主要对MCAL开发及EB tresos工具使用进行总结,仅作为自学使用,以方便后续查漏补缺。 阅读详情

相关推荐

告别“单打独斗”:Oh My Open Code 如何用多模型协作重塑 AI 编程范式

介绍"Oh My OpenCode"——一个能协调多个专业AI模型完成复杂开发任务的智能编程框架。您将看到它如何分配任务、发挥不同模型的独特优势,并通过并行处理和实时纠错等功能解决AI编程流程中的常见痛点。

老孙 | Ethan Sun 的博客:AI 智能体与 AI 原生软件的工程实践 4214

Java多线程:从基本概念到避坑指南,东软java面试题

学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。[外链图片转存中…(img-sgyjLofH-1711650274670)]

2401_83947105的博客 718

告别环境配置焦虑:在Win10的Ubuntu子系统里搞定CSAPP实验环境(附32/64位库编译指南)

本文详细介绍了如何在Win10的Ubuntu子系统中搭建CSAPP实验环境,包括WSL 2的安装与配置、32/64位库的编译指南以及高效开发工具链的设置。通过优化WSL性能和使用实用技巧,开发者可以轻松应对CSAPP实验中的环境配置问题,提升学习效率。

weixin_30443813的博客 297

Java多线程:从基本概念到避坑指南

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。体因为HashMap在进行rehash时,会形成环形链。某些get请求会走到这个环上。JDK并不认为这是个bug,虽然它的影响比较恶劣。如果你判断你的集合类会被多线程使用,那就可以使用线程安全的ConcurrentHashMap来替代它。

2401_84002730的博客 703

[RK3399][Android7.1] 调试笔记 --- 编译GSL5680 touch提示错误

Platform: RK3399 OS: Android 7.1 Kernel: v4.4.83 现象: 之前在rk3288平台上使用过GSL5680的Touch,现在移植过来一直报如下错误: make[1]: `include/generated/vdso-offsets.h' is up to date. CHK include/generated/compi...

Kris Fei's blog 1056

深入解析Zynq Ultrascale+ RF Data Converter中的PLL配置与时钟管理

本文深入解析了Zynq Ultrascale+ RF Data Converter中PLL配置与时钟管理的核心原理与实践。文章将RFDC时钟系统比作交响乐团,详细阐述了PLL作为指挥的关键作用,以及系统时钟、Tile时钟、参考时钟与采样时钟的层级关系。重点剖析了PLL配置参数(如VCO频率、分频器设置)的计算方法与稳定性考量,并提供了从IP配置使能顺序到多Tile同步、DRP访问等常见问题的实战避坑指南与调试技巧,帮助工程师构建稳定的射频信号处理基石。

7up55的博客 452

Java线程池的这几个大坑,你踩过几个?

首先看一个简单的例子:代码可能会抛出空指针异常,但这个异常就会被吞掉。要优雅解决问题,可以为线程池设置一个全局的异常处理器,使用自定义的线程工厂来设置!登录后复制 public class CustomThreadFactory implements ThreadFactory { private final T...

weixin_28914101的博客 178

VCS的增量和分离编译

vcs的增量和分离编译

yunduor909的博客 3303

芋道 yudao-cloud 项目监控

芋道 yudao-cloud 项目通过集成多种开源组件构建完整的监控体系,覆盖应用性能、数据库、日志和链路追踪等维度。主要采用 Spring Boot Admin 实现 JVM 进程监控,SkyWalking 负责链路追踪和日志收集,Druid 监控 MySQL 连接池和 SQL 性能,同时支持 Redis 监控和 Sentinel 服务保障。所有监控系统通过前端菜单统一管理,支持动态配置和灵活扩展。该设计实现了多层次监控能力,用户可根据需求选择组件或替换为 Prometheus 等替代方案。

夏寻的博客 962

MuJoCo 入门教程(一)

在 MuJoCo 仿真中输入自定义数字有三种方法。首先,可在 XML 中定义全局数字字段。它们有一个名称和一个实数值数组。其次,可以通过特定元素的自定义数组来扩展某些模型元素的定义。具体方法是在 XML 元素大小中设置 nuser_XXX 属性。第三,数组 mjData.userdata 不用于任何 MuJoCo 计算。用户可以在这里存储自定义计算的结果;请记住,所有随时间变化的内容都应存储在 mjData 中,而不是 mjModel 中。自定义文本字段可以保存在模型中。

机器人控制与仿真应用 1万+

Jupyter notebook教程系列(二)Jupyter notebook的基本用法

Jupyter notebook的基本使用   一. 主页面 如图1-1 我们先介绍一下主页面上的内容: 1.Files页面是用于管理创建文件相关类目的。 2.Running页面主要展示的是当前正在运行当中的终端和“ipynb”格式的notebook。若想要关闭已经打开的终端和“ipynb”格式的notebook,仅仅关闭其页面是无法彻底退出程序的,需要在Running页面点击其对...

dlhlSC的博客 1438

使用线程池的10个坑

大家好,我是捡田螺的小男孩。日常开发中,为了更好管理线程资源,减少创建线程和销毁线程的资源损耗,我们会使用线程池来执行一些异步任务。但是线程池使用不当,就可能会引发生产事故。今天田螺哥跟大家聊聊线程池的10个坑。大家看完肯定会有帮助的~线程池默认使用无界队列,任务过多导致OOM线程创建过多,导致OOM共享线程池,次要逻辑拖垮主要逻辑线程池拒绝策略的坑Spring内部线程池的坑使用线程池时,没有自定义命名线程池参数设置不合理线程池异常处理的坑使用完线程池忘记关闭。...

weiwenhou的博客 6564

SQL注入详解

SQL注入(SQL Injection)是一种常见的Web安全漏洞,主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。 从而导致数据库受损(被脱库、被删除、甚至整个服务器权限陷)。 即:注入产生的原因是后台服务器接收相关参数未经过滤直接带入数据库查询...

渗透之路,攻防之间皆学问 26万+

线程池 —— 警惕!坑中之王的潜在风险

线程池是 Java 中处理多线程的强大工具,但它不仅仅是“直接用就完事”的工具。很多小伙伴在用线程池时,因为配置不当或忽略细节,踩过许多坑。今天跟大家一起聊聊线程池中容易踩的 10 个坑,以及如何避免这些坑,希望对你会有所帮助。线程池是强大的工具,但如果我们日常工作中用得不好也非常容易踩坑。这篇文章通过实际代码示例,我们可以清楚看到线程池的问题所在及改进方法。希望这些内容能帮你避免踩坑,写出高质量的线程池代码!线程池用得好,效率杠杠的;用得不好,程序天天崩!

深入Java世界:探索编程之美与技术深度 1376

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

线程池原来这么用才稳!一文吃透 ThreadPoolExecutor 核心参数+避坑指南

线程池是Java并发编程中的利器,但很多开发者对其核心参数和工作原理理解不够深入,导致在实际项目中踩坑不断。本文将带你彻底搞懂ThreadPoolExecutor的7大核心参数,通过源码解析+实战示例+避坑指南,让你成为线程池使用高手!理解7大核心参数的含义和相互关系掌握四种拒绝策略的使用场景根据任务类型合理设置线程池大小生产环境务必使用有界队列做好线程池的监控和优雅关闭没有放之四海而皆准的参数配置,需要根据实际业务场景不断调整优化。建议将线程池配置参数化,方便动态调整。

龚小帅的博客 1186

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

用线程池,注意避坑

线程池是 Java 中处理多线程的强大工具,但它不仅仅是“直接用就完事”的工具。很多小伙伴在用线程池时,因为配置不当或忽略细节,踩过许多坑。今天跟大家一起聊聊线程池中容易踩的 10 个坑,以及如何避免这些坑,希望对你会有所帮助。线程池是强大的工具,但如果我们日常工作中用得不好也非常容易踩坑。这篇文章通过实际代码示例,我们可以清楚看到线程池的问题所在及改进方法。希望这些内容能帮你避免踩坑,写出高质量的线程池代码!线程池用得好,效率杠杠的;用得不好,程序天天崩!

kangbin825的专栏 907

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Async 默认线程池真坑!

Async由 Spring 框架提供,被该注解标注的类或方法会由异步线程执行。因此,在项目中,需要异步执行的地方通过@Async指定非常方便,但正是因为这种便利性,让开发人员对底层流程没有任何感知。如果不了解底层原理,直接使用@Async,那就可能会导致在未来的某一时刻出现服务不可用的情况。因为@Async默认使用 Spring 的线程池会为每一个异步任务创建一个线程执行,有 1w 个任务就会创建 1w 个线程,不会对线程进行复用,开销巨大。

qq_45260619的博客 1716

Java线程池的隐藏坑

使用线程池时,如果没有给线程池一个有意义的名称,将不好排查回溯问题。这不算一个坑吧,只能说给以后排查埋坑,因为个人觉得这个还是比较重要的。/***/System.out.println("关注公众号:捡田螺的小男孩");});可以发现,默认打印的线程池名字是pool-1-thread-1,如果排查问题起来,并不友好。因此建议大家给自己线程池自定义个容易识别的名字。System.out.println("关注公众号:捡田螺的小男孩");});

dcp666的博客 715

java线程池的隐藏坑

使用线程池时,如果没有给线程池一个有意义的名称,将不好排查回溯问题。这不算一个坑吧,只能说给以后排查埋坑,因为个人觉得这个还是比较重要的。/***/System.out.println("关注公众号:捡田螺的小男孩");});可以发现,默认打印的线程池名字是pool-1-thread-1,如果排查问题起来,并不友好。因此建议大家给自己线程池自定义个容易识别的名字。System.out.println("关注公众号:捡田螺的小男孩");});

z1ztai的博客 1130

【踩坑指南】线程池使用不当的五个坑

本文给大家介绍了线程池使用不当的五个坑,分别是线程池中异常消失、线程池决绝策略设置错误、重复创建线程池导致内存溢出、使用同一个线程池执行不同类型的任务、使用 ThreadLocal 和线程池的不兼容问题,以及它们的问题原因和解决方法。希望这些内容对大家有帮助。

Gefangenes的博客 1896

浅聊一下线程池的10个坑

使用线程池时,如果没有给线程池一个有意义的名称,将不好排查回溯问题。这不算一个坑吧,只能说给以后排查埋坑,哈哈。我还是单独把它放出来算一个点,因为个人觉得这个还是比较重要的。});Hello,Java可以发现,默认打印的线程池名字是,如果排查问题起来,并不友好。因此建议大家给自己线程池自定义个容易识别的名字。其实用});

程序员高级码农的博客 1078

没想到,这么简单的线程池用法,深藏这么多坑!

又又又踩坑了 生产有个对账系统,每天需要从渠道端下载对账文件,然后开始日终对账。这个系统已经运行了很久,前两天突然收到短信预警,没有获取渠道端对账文件。 ps:对账系统详细实现方式:对账系统设计与实现 本以为又是渠道端搞事情,上去一排查才发现,所有下载任务都被阻塞了。再进一步排查源码,才发现自己一直用错了线程池某个方法。 由于线程创建比较昂贵,正式项目中我们都会使用线程池执行异步任务。线程池,使用池化技术保存线程对象,使用的时候直接取出来,用完归还以便使用。 虽然线程池的使用非常方法非常简单,但是越简单

楼下小黑哥 1162

线程池使用的10个坑

日常开发中,为了更好管理线程资源,减少创建线程和销毁线程的资源损耗,我们会使用线程池来执行一些异步任务。但是线程池使用不当,就可能会引发生产事故。今天跟大家聊聊线程池的10个坑。大家看完肯定会有帮助的~线程池默认使用无界队列,任务过多导致OOM线程创建过多,导致OOM共享线程池,次要逻辑拖垮主要逻辑线程池拒绝策略的坑Spring内部线程池的坑使用线程池时,没有自定义命名线程池参数设置不合理线程池异常处理的坑使用完线程池忘记关闭。

l688899886的博客 2270
上一篇: 一款专注 Spring 源码学习的神器,帅呆了!
下一篇: 离职4个月后,前领导竟然半夜让我改方案!他说明早9点要用,我灵机一动答应他8点交付!挂掉电话后,我彻底拉黑了领导,微笑入睡!...
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值