Java线程池原理、使用规范、常用并发异步工具类
本文全覆盖:线程池核心原理、七大参数详解、工作机制、拒绝策略、内置线程池弊端、生产自定义线程池、线程池复用原理、四大并发异步工具类,解决线程池95%面试和线上问题,逻辑闭环、可直接背诵。
一、线程池核心原理(为什么用线程池)
1. 原生new Thread的弊端
- 频繁创建、销毁线程,开销极大(OS内核线程创建成本高)
- 无限制创建线程,导致线程泛滥、上下文切换爆炸、OOM
- 缺乏统一管理、任务排队机制
2. 线程池核心作用
线程复用、控制并发、统一管理、降低开销
- 复用线程:线程创建一次,循环处理任务,避免频繁销毁创建
- 限流保护:控制最大并发线程数,保护服务器CPU、内存资源
- 任务队列缓冲:削峰填谷,应对突发流量
- 可监控、可拒绝、可优雅关闭
二、线程池七大核心参数(面试必考)
ThreadPoolExecutor 完整构造器7个参数,是线程池底层核心
- corePoolSize 核心线程数:常驻线程,不会被超时回收
- maximumPoolSize 最大线程数:线程池允许的最大并发线程数量
- keepAliveTime 空闲超时时间:非核心线程空闲超时后被回收
- unit 时间单位:配合超时时间使用
- workQueue 任务阻塞队列:存放等待执行的任务
- threadFactory 线程工厂:创建线程,自定义线程名、优先级、守护线程
- handler 拒绝策略:任务满负荷后,新任务的处理策略
三、线程池完整工作流程(满分背诵)
任务提交执行顺序:核心线程 → 队列 → 最大线程 → 拒绝策略
- 提交任务,判断当前线程数 < 核心线程数:新建核心线程执行任务
- 核心线程已满,判断队列是否未满:任务放入阻塞队列排队
- 队列已满,判断当前线程数 < 最大线程数:新建非核心线程执行任务
- 达到最大线程数 + 队列已满:触发拒绝策略
- 非核心线程空闲超过 keepAliveTime:自动回收,节省资源
四、四大拒绝策略(JDK内置)
- AbortPolicy(默认):直接抛出异常,中断任务,生产不推荐
- CallerRunsPolicy:谁提交谁执行(主线程自己跑),不抛异常、不丢任务,生产最稳
- DiscardPolicy:直接丢弃当前新任务,无日志、无异常,风险高
- DiscardOldestPolicy:丢弃队列最老任务,执行新任务,适合实时性任务
五、四种内置线程池 & 致命弊端(阿里规范)
生产禁止使用 Executors 内置线程池!全部存在隐患
1. FixedThreadPool(固定线程池)
- 核心线程=最大线程,无空闲回收
- 弊端:队列是无界队列 LinkedBlockingQueue,任务无限堆积 → OOM
2. CachedThreadPool(缓存线程池)
- 核心线程0,最大线程Integer.MAX_VALUE
- 弊端:线程无限创建 → 线程泛滥、CPU打满、OOM
3. SingleThreadExecutor(单线程池)
- 单个线程串行执行
- 弊端:无界队列,任务堆积OOM
4. ScheduledThreadPool(定时线程池)
- 支持定时、周期任务
- 弊端:最大线程数无限,高并发线程爆炸
六、生产环境正确使用方式(必背)
手动自定义 ThreadPoolExecutor + 有界队列 + 自定义线程名 + 合理拒绝策略
- 队列必须使用 有界队列(如ArrayBlockingQueue),限制任务数量,防止OOM
- 自定义线程工厂,设置线程名称,方便线上排查堆栈
- 拒绝策略优先使用 CallerRunsPolicy,保证不丢任务、不抛异常雪崩
- 根据业务IO密集/CPU密集配置参数
参数配置经验值
- CPU密集型:核心线程数 = CPU核心数 + 1(减少上下文切换)
- IO密集型:核心线程数 = CPU核心数 * 2 或 20–50(等待IO,可多开线程)
七、线程池核心拓展知识点
1. 线程池线程复用原理
线程启动后不会退出,底层通过 while死循环 + 队列take() 不断阻塞获取新任务,实现线程永久复用,只有线程超时/关闭才会退出。
2. 核心线程会不会回收?
默认不会。可通过 allowCoreThreadTimeOut(true) 开启核心线程超时回收,极致节省资源。
3. 线程池关闭方式
- shutdown():平缓关闭,停止接收新任务,执行完队列剩余任务
- shutdownNow():强制关闭,尝试中断正在执行任务,清空队列
八、Java 四大常用并发/异步工具类(面试高频)
1. CompletableFuture(JDK8 异步编程神器)
解决问题:替代 Future,解决回调地狱、无法链式编程、获取结果阻塞问题,实现全异步链式编程。
核心能力
- 异步执行任务、非阻塞获取结果
- 链式调用:thenApply、thenAccept、thenRun
- 多任务组合:allOf(全部完成)、anyOf(任意一个完成)
- 异常优雅捕获
适用场景
多接口并行查询、复杂异步编排、微服务多接口聚合、批量异步处理
2. CountDownLatch(倒计时计数器)
核心作用:一个线程等待多个线程执行完毕,一次性使用、不可重置。
原理
- 构造传入总次数count
- 子线程执行完调用 countDown() 计数器-1
- 主线程 await() 阻塞,直到count=0唤醒
场景
多线程批量任务、并行处理后汇总结果
3. CyclicBarrier(循环栅栏)
核心作用:多个线程互相等待,全部到位再统一执行,可循环复用。
区别CountDownLatch
- CountDownLatch:主线等子线程,一次性
- CyclicBarrier:子线程互相等,可循环复用
场景
多阶段分批任务、多人组队同步执行、循环批量处理
4. Semaphore(信号量)
核心作用:控制并发限流,限制同时执行的线程数量
原理
- permits 许可数 = 最大并发数
- acquire() 获取许可,没有则阻塞
- release() 释放许可
场景
接口限流、数据库连接限流、第三方接口调用限流、秒杀并发控制
九、四大并发工具类终极对比(背诵版)
- CountDownLatch:倒计时,主线等子线程,一次性
- CyclicBarrier:栅栏等待,线程互相等,可循环
- Semaphore:并发限流,控制同时运行线程数
- CompletableFuture:异步任务编排、多任务组合、链式异步编程
十、面试终极总结(直接背诵)
线程池通过线程复用降低创建销毁开销,通过七大参数控制并发与排队;工作流程遵循核心线程→队列→最大线程→拒绝策略。禁止使用JDK内置线程池,必须自定义有界队列线程池防止OOM。并发工具中,CountDownLatch用于批量等待、CyclicBarrier用于循环同步、Semaphore用于限流、CompletableFuture用于异步任务编排。