目录
工作线程本质就是一个Worker对象。再究其底层,其实就是thread.start启动的线程。
addWorker()源码剖析 (线程池如何添加工作线程?)
runWorker()源码剖析 (工作线程如何执行的任务?)
- 为什么要有线程池?
- Java是实现和管理线程池有哪些方式? 请简单举例如何使用。
- 为什么很多公司不允许使用Executors去创建线程池? 那么推荐怎么使用呢?
- ThreadPoolExecutor有哪些核心的配置参数? 请简要说明
- ThreadPoolExecutor可以创建哪三种线程池呢?
- 当队列满了并且worker的数量达到maxSize的时候,会怎么样?
- 说说ThreadPoolExecutor有哪些RejectedExecutionHandler策略? 默认是什么策略?
- 简要说下线程池的任务执行机制? execute –> addWorker (增加工作线程)–>runworker (getTask) (工作线程执行任务)
- 线程池中任务是如何提交的?
- 线程池中任务是如何关闭的?
- 在配置线程池的时候需要考虑哪些配置因素?
- 如何监控线程池的状态?
为什么要有线程池
减少性能开销:如果每次执行异步任务,都去构建一个全新的线程执行,但是任务执行完毕后,线程还要销毁。可以利用线程池,实现资源复用,线程处理完任务,不会立即销毁,而是等待新任务的到来。类似连接池。
可以充分发挥CPU性能:如果每次来任务都直接new,没有办法去把控线程的个数。如果太多了,上下文频繁的切换,性能有损耗。如果太少了,CPU资源没有发挥出来。线程池可以指定好工作线程的个数,充分发挥CPU资源。
监控的效果:如果直接new的话,无法查看线程的个数或者工作的状态。但是采用了线程池之后,本身帮咱们记录很多信息,工作线程个数,有多少个任务在排队,每一个工作线程处理了多少个任务,整个线程池处理了多少个任务
ThreadPoolExecutor应用方式
手动创建ThreadPoolExecutor
1、只需要构建好ThreadPoolExecutor对象即可,传入指定的7个参数。
2、在执行Runnable任务时,可以直接调用execute方法执行。
3、在执行Callable任务时,需要有返回结果,直接调用submit方法执行。
线程池的核心参数
工作线程本质就是一个Worker对象。再究其底层,其实就是thread.start启动的线程。
线程池的执行流程 (excute()方法的执行过程)
线程池的状态
线程池中的核心属性ctl
解释一个AtomicInteger是个什么鬼?
1、可以简单的看成,AtomicInteger就是一个int数值。
2、因为线程池中存在并发修改ctl的情况。AtomicInteger内部是基于CAS的方式,对ctl属性做修改。
Ps:CAS其实就是比较和交换,Compare And Swap。基于CPU支持的原语,来保证的原子性。保证修改某一个属性的时候,是原子性的。
ctl在线程池中,维护这两个信息:
- 工作线程的个数。
- 线程池的状态。
一个int类型,怎么维护这两个信息?线程池内部,将这个本质是int类型的ctl,拆分为32个bit位。
线程池的状态变化
线程池的状态
线程池中常用的两个函数
状态转化
线程池需要执行任务时,需要始终保证running状态
shutdown()
shutdownNow()
tryTerminate() 内部调用
terminated()
重写该方法,线程池销毁之后需要执行什么操作