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

Java并发编程之线程池详解

关键词:Java 并发、线程池、ThreadPoolExecutor、线程管理、线程复用、性能优化


✅ 摘要

在高并发系统中,频繁地创建和销毁线程会带来显著的性能开销。为了解决这个问题,Java 提供了线程池机制来统一管理和复用线程资源。线程池是 Java 并发编程中的核心组件之一,广泛应用于任务调度、异步处理、定时任务等场景。

本文将全面讲解 Java 中线程池的核心概念、工作原理、常见参数配置、拒绝策略、自定义线程池、最佳实践等内容,并提供大量 可运行的示例代码,帮助你深入理解线程池的使用方式与底层机制。


📌 一、为什么需要线程池?

1.1 线程的生命周期成本

每次新建一个线程都要进行:

  • 内存分配
  • 栈空间初始化
  • 线程注册操作系统资源
  • 调度器调度线程执行

这些操作在高并发下会产生明显的性能瓶颈。

1.2 线程池的作用

  • 线程复用:避免频繁创建和销毁线程
  • 控制最大并发数:防止系统因线程过多而崩溃
  • 任务队列管理:实现任务排队、延迟执行等功能
  • 提高响应速度:线程提前准备好,直接执行任务

📌 二、Java 中的线程池体系结构

2.1 主要类图关系

Executor↑
ExecutorService↑
AbstractExecutorService↑
ThreadPoolExecutor
  • Executor:最顶层接口,只有一个 execute(Runnable) 方法
  • ExecutorService:扩展了提交任务的方法(submit)、关闭方法等
  • ThreadPoolExecutor:线程池的核心实现类

📌 三、线程池的核心参数详解

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
参数说明
corePoolSize核心线程数,即使空闲也不会被回收
maximumPoolSize最大线程数,当任务队列满时可以扩容至该值
keepAliveTime非核心线程的最大存活时间
unit存活时间单位
workQueue任务等待队列
threadFactory创建新线程的工厂
handler拒绝策略

📌 四、线程池的工作流程详解

线程池的任务执行流程如下:

  1. 如果当前线程数 < corePoolSize,则新建线程执行任务;
  2. 否则,将任务加入阻塞队列;
  3. 如果队列已满且当前线程数 < maximumPoolSize,则新建非核心线程执行任务;
  4. 如果队列已满且线程数 >= maximumPoolSize,则触发拒绝策略。

📌 注意:如果使用无界队列(如 LinkedBlockingQueue),maximumPoolSize 将失效。


📌 五、常见的线程池类型(Executors 工具类)

Java 提供了几个常用的线程池工厂方法:

5.1 固定大小线程池(FixedThreadPool)

ExecutorService executor = Executors.newFixedThreadPool(5);
  • 核心线程数 = 最大线程数
  • 使用无界队列(LinkedBlockingQueue
  • 适用于负载较重、任务数量稳定的场景

5.2 缓存线程池(CachedThreadPool)

ExecutorService executor = Executors.newCachedThreadPool();
  • 核心线程数为 0,最大线程数为 Integer.MAX_VALUE
  • 非核心线程超时时间为 60 秒
  • 适用于执行大量短期异步任务的场景

5.3 单线程线程池(SingleThreadExecutor)

ExecutorService executor = Executors.newSingleThreadExecutor();
  • 只有一个线程,保证任务顺序执行
  • 使用无界队列
  • 适用于需要顺序执行任务的场景

5.4 定时任务线程池(ScheduledThreadPool)

ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
executor.scheduleAtFixedRate(() -> {System.out.println("每两秒执行一次");
}, 0, 2, TimeUnit.SECONDS);
  • 支持定时任务和周期性任务执行
  • 常用于心跳检测、日志采集、定时清理等场景

📌 六、线程池的拒绝策略

当任务无法提交时(队列满 + 线程数已达上限),线程池会调用拒绝策略处理器。

Java 提供了以下几种内置拒绝策略:

策略行为
AbortPolicy(默认)抛出 RejectedExecutionException 异常
CallerRunsPolicy由调用线程(提交任务的线程)自己执行该任务
DiscardOldestPolicy丢弃队列中最老的一个任务,尝试再次提交
DiscardPolicy默默丢弃任务,不抛异常也不执行
自定义拒绝策略示例:
RejectedExecutionHandler handler = (r, executor) -> {System.out.println("任务被拒绝:" + r.toString());
};ExecutorService executor = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS,new ArrayBlockingQueue<>(2), new ThreadPoolExecutor.CallerRunsPolicy()
);

📌 七、线程池的最佳实践

7.1 不要使用 Executors 工厂方法创建线程池(推荐自定义)

因为:

  • newFixedThreadPoolnewSingleThreadExecutor 使用的是 无界队列,可能导致内存溢出
  • newCachedThreadPool 的最大线程数是无限的,可能耗尽系统资源

✅ 推荐做法:使用 ThreadPoolExecutor 显式指定参数

ExecutorService executor = new ThreadPoolExecutor(5, 10,60L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),new ThreadPoolExecutor.AbortPolicy()
);

7.2 合理设置参数

场景推荐参数
CPU 密集型任务corePoolSize = CPU核心数
IO 密集型任务corePoolSize = CPU核心数 * 2
高吞吐任务设置较大的队列容量和合理的拒绝策略

7.3 关闭线程池

executor.shutdown(); // 温和关闭,不再接受新任务,等待已有任务完成
executor.shutdownNow(); // 强制关闭,尝试中断正在执行的任务

📌 八、线程池的监控与调试

可以通过继承 ThreadPoolExecutor 或使用 ThreadPoolTaskExecutor(Spring 提供)来监控线程池状态。

@Override
protected void beforeExecute(Thread t, Runnable r) {System.out.println("任务开始执行:" + r);
}@Override
protected void afterExecute(Runnable r, Throwable t) {System.out.println("任务结束执行:" + r);
}

📌 九、完整示例代码

import java.util.concurrent.*;public class ThreadPoolDemo {public static void main(String[] args) {ExecutorService executor = new ThreadPoolExecutor(2, 4,60L, TimeUnit.SECONDS,new ArrayBlockingQueue<>(2),new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 10; i++) {final int taskNo = i;executor.execute(() -> {System.out.println("执行任务 " + taskNo + ",线程:" + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}executor.shutdown();}
}

✅ 总结

特性说明
线程池作用提高线程复用率、降低系统开销
核心参数corePoolSize、maximumPoolSize、workQueue、handler
工作流程核心线程 → 队列 → 扩容 → 拒绝
拒绝策略Abort、CallerRuns、DiscardOldest、Discard
最佳实践显式创建线程池、合理设置参数、优雅关闭
应用场景并发请求处理、定时任务、批量数据处理等

📚 参考资料

  • Java 官方文档 - ExecutorService
http://www.dtcms.com/a/279911.html

相关文章:

  • openGL学习(Shader)
  • 【面板数据】全国地级市逐日空气质量指数AQI数据集(2013-2024年)
  • 代码随想录算法训练营第四十九天|单调栈part2
  • Java强化:IO流
  • 正则表达式替换中使用 g<0> 引用整个匹配的内容
  • vim扩展与 neovim
  • IOS开发者账号如何添加 uuid 原创
  • Doris
  • 20250714--长连接应用中ORA-04061: existing state of has been invalidated
  • 迪拜金融市场交易量激增,中阿资本合作深化——阿联酋交易所系统解决方案全景解析
  • Transformer江湖录 第七章:江湖新篇 - Transformer的现代演化
  • FilterRegistationBean报错does not have type parameters。idea启动日志无明显报错提示冲突 kaki的博客
  • 力扣-25.K个一组翻转链表
  • 多线程进阶——线程安全的集合类
  • B站自动回复工具(破解)
  • Linux多进程
  • 国产IP摄像头存在隐蔽后门,攻击者可获取Root权限
  • 知识点2:MCP:python-sdk 核心概念
  • 丑团-h5-Mtgsig算法-分析
  • 技能升级--二分例题
  • 2025年大数据、建模与智能计算国际会议(ICBDMIC 2025)
  • 指针和数组(二)
  • AI 临床医学课题【总结】
  • Vue2 day08-10(智慧商城)
  • 应用系统报错:com.highgo.jdbc.util.PSQLException:bad value for long(APP)
  • DOM事件绑定时机:解决脚本提前加载导致的绑定失败
  • git modules
  • 8.6 Rag-基础工具介绍(开源工具)
  • 5、qt系统相关
  • 面试150 根节点到叶子节点数字之和