“兄弟,听说你最近在面试 Java 开发?”
“是啊,昨天刚面了个大厂,结果一上来就问我线程池的创建方式,差点没给我问懵了……”
“线程池啊?这可是 Java 多线程编程的必考点啊!不过你别慌,今天咱们就来系统地复习一下这个知识点,保证你下次遇到这种问题,稳稳拿下!”
什么是线程池?
在正式聊线程池之前,我们先来看看下面这个场景。
假设你是一家餐厅的老板,生意火爆,每天都有大量顾客上门点餐。如果你让每位顾客进店时都临时招聘一个厨师来做饭,那不仅招聘成本高,厨师培训慢,顾客等得也烦。有没有更好的办法呢?
当然有!你可以雇佣一支固定的厨师团队,来回轮流做饭。这样不仅节省了招聘时间,还能让厨师们各司其职,提高效率。
在 Java 里,线程池(ThreadPool)就类似于这个厨师团队的概念。它的作用是:
- 预先创建一批线程,并复用它们来执行任务,避免频繁创建和销毁线程带来的开销。
- 统一管理线程,提高线程的调度效率。
- 控制并发量,防止系统因创建过多线程导致崩溃。
总结一下,线程池的本质就是管理和复用一批线程,以提高系统的并发性能并降低线程创建的开销。
线程池的创建方式
在 Java 里,线程池主要是由 ExecutorService 接口提供的,而 ThreadPoolExecutor 是它的核心实现类。创建线程池的方式主要有以下几种:
直接使用 ThreadPoolExecutor 构造方法(推荐)
参数说明:
- 核心线程数(corePoolSize) :线程池中始终存活的线程数量,即使它们空闲也不会被回收。
- 最大线程数(maximumPoolSize) :线程池中允许的最大线程数,当任务量增加时,线程数最多可以扩展到这个值。
- 线程空闲时间(keepAliveTime) :如果线程数超过 corePoolSize,那么多余的线程在 keepAliveTime 时间内没有新任务时会被销毁。
- 任务队列(BlockingQueue) :用于存放等待执行的任务,如 LinkedBlockingQueue、ArrayBlockingQueue 等。
- 线程工厂(ThreadFactory) :用于创建线程,通常使用默认的 Executors.defaultThreadFactory() 即可。
- 拒绝策略(RejectedExecutionHandler) :当任务数量超过线程池负荷时,如何处理新任务:
-
- AbortPolicy(默认):直接抛出 RejectedExecutionException 异常。
-
- CallerRunsPolicy:由提交任务的线程自己执行该任务。
-
- DiscardPolicy:直接丢弃任务,不抛异常。
-
- DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试重新提交当前任务。
使用 Executors 工具类创建(不推荐)
Java 提供了 Executors 工具类来简化线程池的创建:
但不推荐使用 Executors 的原因是:
- FixedThreadPool 和 SingleThreadExecutor 使用的是无界队列,可能导致 OOM(内存溢出)。
- CachedThreadPool 线程数无限增长,容易导致 CPU 负载过高。
- ScheduledThreadPool 适用于定时任务,但如果任务堆积,可能影响调度精准度。
最佳实践:使用 ThreadPoolExecutor 进行精细化管理!
线程池的优点
线程池在高并发系统中至关重要,它的主要优点包括:
- 降低资源消耗:线程复用减少了频繁创建和销毁线程的开销,提高了系统效率。
- 提高响应速度:任务可以快速被已有的线程执行,而无需等待新线程创建。
- 提高线程管理能力:线程池提供了任务队列、线程复用、超时回收、拒绝策略等机制,使线程管理更加灵活。
- 防止资源耗尽:可以限制最大线程数,防止线程数量过多导致内存溢出或 CPU 过载。
- 增强系统稳定性:合理的线程池策略能让系统在高负载下仍能稳定运行。
线程池的生命周期(五种状态)
线程池的运行状态主要有五种:
- RUNNING(运行中) :可以接受新任务,并处理队列中的任务。
- SHUTDOWN(关闭中) :调用 shutdown() 方法后,线程池不再接受新任务,但会继续执行队列中的任务。
- STOP(停止) :调用 shutdownNow() 方法后,线程池立即终止所有线程,不再执行任务。
- TIDYING(整理中) :当所有任务执行完毕,线程池的线程数为 0 时,进入 TIDYING 状态,执行 terminated() 方法。
- TERMINATED(已终止) :线程池彻底终结,不再接受任何任务。
示例:
结语
线程池是 Java 并发编程的重要工具,合理使用线程池能显著提升系统性能和稳定性。在面试时,如果被问到线程池,你可以按照如下结构回答:
- 什么是线程池? (概念和作用)
- 如何创建线程池? (ThreadPoolExecutor vs Executors)
- 线程池的优点? (节省资源、提高性能、增强稳定性)
- 线程池的状态? (RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED)
掌握这些核心知识点,保证你在 Java 面试中更胜一筹!
END
如果这篇文章对你有帮助,欢迎点赞、收藏、转发!你对 Java 线程池还有什么疑问吗?欢迎在评论区讨论!
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!