前言
线程池是Java并发编程的核心组件,也是面试必考题。本文从原理到实战,带你全面掌握线程池的7个关键点。
一、为什么需要线程池?
每次创建线程都有开销:
- 线程创建需要调用系统API,开销大
- 线程销毁也需要开销
- 大量线程会消耗内存
线程池解决问题:
- 线程复用,减少创建销毁开销
- 控制最大并发数
- 提供任务队列,缓冲突发请求
二、线程池核心参数
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)
三、线程池执行流程
- 任务来了,核心线程数未满 → 创建核心线程执行
- 核心线程已满,队列未满 → 任务加入队列
- 队列已满,线程数未达最大值 → 创建非核心线程执行
- 线程数已达最大值 → 执行拒绝策略
四、4种拒绝策略
- AbortPolicy:直接抛异常(默认)
- CallerRunsPolicy:由调用线程执行任务
- DiscardPolicy:直接丢弃,不抛异常
- DiscardOldestPolicy:丢弃队列中最老的任务
五、常见线程池
// 固定大小线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(10);
// 缓存线程池(线程数无限,适合短期异步任务)
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 单线程线程池
ExecutorService singlePool = Executors.newSingleThreadExecutor();
// 定时任务线程池
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
六、线程池最佳实践
CPU密集型任务:核心线程数 = CPU核数 + 1
IO密集型任务:核心线程数 = CPU核数 * 2
// 推荐用法:手动创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadFactoryBuilder().setNamePrefix("my-pool-").build(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
七、线程池监控
// 关键指标
executor.getActiveCount(); // 活跃线程数
executor.getQueue().size(); // 队列任务数
executor.getCompletedTaskCount(); // 已完成任务数
executor.getPoolSize(); // 当前线程数
总结
掌握线程池的7个关键点,不仅能在面试中游刃有余,更能在实际项目中写出高性能的并发程序。
本文由AI辅助创作。
文章摘自:https://www.cnblogs.com/czlws/p/19769257
