Java线程池详解
一、简介
Java线程池是Java并发学习中的一个重要知识点,线程池在实际开发过程中有着重要的作用,也是面试过程中重要的考题。
二、线程池运行机制
2.1 主要参数简介
- 核心线程数
线程池初始化时线程池中线程的数目 - 最大线程数
当队列满时,线程池能够创建线程的最大数目 - 等待队列
当核心线程都被占用时,将后续的任务放到等待队列中等待调度 - 拒绝策略
线程池不能再接收新任务时,执行拒绝策略。 - 创建工厂
与实际生产中查错相关,追溯源头(来自阿里面试) - 其他参数
2.2 运行机制
运行流程图
2.3 相关参数详解
等待队列: 等待队列主要分为两种,有界队列和无界队列。当等待队列设置为无解队列时,最大线程数失效,可能会导致的问题就是系统资源耗尽。
拒绝策略: 线程池的主要有四种拒绝策略(线程池的拒绝策略体现设计模式中的策略模式)
- CallerRunsPolicy - 当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大
- AbortPolicy - 丢弃任务,并抛出拒绝执行RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行。
- DiscardPolicy - 直接丢弃。
- DiscardOldestPolicy - 当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
线程数如何确定:
- IO密集型 2N;
- CPU密集型 N + 1
2.4 线程销毁
由于非核心线程是为了解决任务过多的时候临时增加的,所以当任务处理完成后,工作线程处于空闲状态的时候,就需要回收。
通过设计keepAliveTime实现
- 线程销毁的两种场景:
① allowCoreThreadTimeOut == true,核心线程和非核心线程空闲keepAliveTime时被销毁,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
② allowCoreThreadTimeOut == false,非核心线程空闲keepAliveTIme时被销毁,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) - 核心线程永不销毁的场景
① allowCoreThreadTimeOut == false,核心线程永不销毁。workQueue.take()阻塞当前线程。
参考 https://www.cnblogs.com/wqff-biubiu/p/12589450.html
三、线程池的好处
- 降低资源消耗。通过重复利用机制降低线程创建和销毁造成的消耗
- 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行
- 提高线程的可管理性。线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控