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

Java线程池详解

一、线程池是什么

以学校奶茶店招聘兼职为例:如果每次有订单都临时雇人送快递(创建线程),招聘成本(线程创建/销毁开销)将变得极高。线程池就像老板预先雇佣3个固定配送员(核心线程),高峰期临时增加人手(最大线程数),空闲时回收资源,有效解决了频繁创建/销毁线程的性能损耗问题。

二、标准库中的线程池 

1. Executors工厂方法

Java通过java.util.concurrent.Executors提供多种预置线程池:

// 固定线程数的线程池(核心=最大线程数)
ExecutorService fixedPool = Executors.newFixedThreadPool(10); // 弹性伸缩线程池(核心0,最大Integer.MAX_VALUE,空闲60秒回收)
ExecutorService cachedPool = Executors.newCachedThreadPool();// 单线程池(保证任务顺序执行)
ExecutorService singlePool = Executors.newSingleThreadExecutor();// 支持定时/周期任务的线程池
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);

一般使用第一个和第二个比较多

2. 终极构造器:ThreadPoolExecutor

所有预置线程池底层均通过ThreadPoolExecutor实现,其完整构造方法如下:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler
)

构造方法参数解析

1. 核心线程控制
参数说明
corePoolSize核心线程数,即使空闲也不会销毁(除非allowCoreThreadTimeOut=true)
maximumPoolSize线程池允许的最大线程数(含核心线程)

​示例​​:core=5, max=10,当任务队列满时,线程数可扩容到10

2. 线程存活策略
参数说明
keepAliveTime非核心线程的空闲存活时间(默认60秒)
unit时间单位(秒/毫秒等)
3. 任务队列

BlockingQueue<Runnable> workQueue 的三种典型选择:

队列类型行为特点适用场景
SynchronousQueue不存储任务,直接移交线程高吞吐量(newCachedThreadPool)
LinkedBlockingQueue无界队列(默认Integer.MAX_VALUE)固定线程数(newFixedThreadPool)
ArrayBlockingQueue有界队列,需指定容量流量削峰
4. 线程工厂与拒绝策略
参数说明
threadFactory自定义线程创建方式(可设置线程名、优先级等)
RejectedExecutionHandler任务拒绝策略(当队列满且线程数达max时触发)

四大内置拒绝策略​​:

  • AbortPolicy(默认):抛出RejectedExecutionException
  • CallerRunsPolicy:由提交任务的线程直接执行
  • DiscardPolicy:静默丢弃任务
  • DiscardOldestPolicy:丢弃队列最老任务并重试

参数配置实践建议

  • ​CPU密集型任务​​:核心数 ≈ CPU核数(避免过多线程导致频繁上下文切换)
  • ​IO密集型任务​​:核心数可适当增大(如2*CPU核数)
  • ​混合型任务​​:拆分线程池隔离处理(如计算任务与IO任务使用不同池)
  • ​队列选择​​:需要限流时使用有界队列,配合合理的拒绝策略

 关于工厂模式,会有这个东西,其实是因为构造方法的局限性,比如两种构造方法参数列表相同导致无法重载,构造方法名称固定,无法通过方法名表达语义差异,对象创建逻辑与类本身耦合过紧

// 错误示例:参数类型相同导致编译错误
class Coordinate {
    // 尝试用极坐标和直角坐标两种构造方式
    public Coordinate(double r, double theta) {} // 极坐标
    public Coordinate(double x, double y) {}     // 直角坐标 ❌编译错误
}

这时就会出现编译错误,解决方法,就是单独创建一个类,来实现不同的构造方法.工厂模式本质是通过将对象的实例化过程委托给专门的工厂类,解决了构造方法在语义表达和参数灵活性上的先天不足,是面向对象设计中"封装变化"原则的典型实践。

三、实现线程池 

  • 核心操作为 submit, 将任务加入线程池中
  • 使用 Worker 类描述一个工作线程. 使用 Runnable 描述一个任务.
  • 使用一个 BlockingQueue 组织所有的任务
  • 每个 worker 线程要做的事情: 不停的从 BlockingQueue 中取任务并执行.
  • 指定一下线程池中的最大线程数 maxWorkerCount; 当当前线程数超过这个最大值时, 就不再新增 线程了.
/*** 工作线程类,负责从任务队列获取并执行任务* 继承Thread类实现多线程能力*/
class Worker extends Thread {// 线程共享的任务队列(注意泛型应为Runnable)private LinkedBlockingQueue<Runnable> queue;/*** 构造函数初始化任务队列* @param queue 线程池共享的任务阻塞队列*/public Worker(LinkedBlockingQueue<Runnable> queue) {super("worker");this.queue = queue;}@Overridepublic void run() {try {// 持续监听任务队列(建议将中断检查放在循环条件中)while (!Thread.interrupted()) {// 阻塞式获取任务,队列为空时线程等待Runnable task = queue.take();task.run(); // 执行任务}} catch (InterruptedException e) {// 被中断时退出线程(保持线程终止的响应能力)}}
}/*** 简易线程池实现类* 包含任务队列和工作线程管理*/
public class MyThreadPool {// 最大工作线程数(根据需求调整)private int maxWorkerCount = 10;// 线程安全的任务队列(使用阻塞队列保证线程安全)private LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();/*** 提交任务到线程池* @param command 待执行的任务*/public void submit(Runnable command) {// 当工作线程不足时创建新线程(需添加当前工作线程数统计)// 示例代码此处逻辑不完整,建议补充:// if(当前线程数 < maxWorkerCount) {//     new Worker(queue).start();// }try {queue.put(command); // 将任务加入队列(阻塞直到添加成功)} catch (InterruptedException e) {Thread.currentThread().interrupt();}}public static void main(String[] args) throws InterruptedException {MyThreadPool pool = new MyThreadPool();// 提交示例任务pool.submit(() -> {System.out.println("吃饭"); // 具体任务逻辑});Thread.sleep(1000); // 主线程等待}
}// 总结-线程安全实现要点:
// 1. 使用LinkedBlockingQueue保证队列操作的线程安全性
// 2. take()/put()方法的阻塞特性自然实现线程等待
// 3. 工作线程通过共享队列实现任务分配
// 4. InterruptedException处理保证线程终止能力

四、总结

Java线程池通过ThreadPoolExecutor提供高度可定制的并发控制能力。理解每个参数对系统性能的影响(如队列容量与最大线程数的平衡),能够帮助开发者构建出高吞吐、低延迟的线程管理体系。建议根据具体业务场景,结合监控数据动态调整参数,方能发挥线程池的最大效能。

http://www.xdnf.cn/news/183133.html

相关文章:

  • 2024年12月GESP 图形化 一级考级真题——飞行的小猫
  • Linux的例行性工作(crontab)
  • 码蹄杯——tips
  • MAGI-1: Autoregressive Video Generation at Scale
  • 基于Jamba模型的天气预测实战
  • java工具类
  • Redis哨兵模式深度解析:实现高可用与自动故障转移的终极指南
  • 大语言模型架构基础与挑战
  • 简单了解Java的I/O流机制与文件读写操作
  • 智能电网新引擎:动态增容装置如何解锁输电线路潜力?
  • spark学习总结
  • C++/SDL 进阶游戏开发 —— 双人塔防(代号:村庄保卫战 14)
  • Java大厂面试:互联网医疗场景中的Spring Boot与微服务应用
  • 第42周:文献阅读
  • 杭州小红书代运营公司-品融电商:专业赋能品牌社交增长
  • Java + Spring Boot + MyBatis获取以及持久化sql语句的方法
  • 单片机之间的双向通信
  • 可视化图解算法: 二叉搜索树转双向排序链表
  • Spdlog 日志组件的安装及使用
  • 【C语言】程序分配的区域
  • spring框架学习(下)
  • 现场问题排查-postgresql某表索引损坏导致指定数据无法更新影响卷宗材料上传
  • Java异常处理全面指南:从基础到高级实践
  • (done) 吴恩达版提示词工程 6. 转换 (翻译,通用翻译,语气风格变换,文本格式转换,拼写检查和语法检查)
  • 关于定时任务原理
  • Python实例题:Python气象数据分析
  • 猿人学web端爬虫攻防大赛赛题第15题——备周则意怠-常见则不疑
  • Linux Centos8使用yum命令安装mysql8
  • 《100天精通Python——基础篇 2025 第9天:字典操作全解析与哈希原理揭秘》
  • SAE 实现应用发布全过程可观测