架构阅读笔记6
线程是一种宝贵的资源,并且是一种有限的资源,创建和销毁线程也需要付出不菲的代价。我们所有的代码都是由一个一个的线程支撑起来的,如今的芯片架构也决定了我们必须编写多线程执行的程序,以获取最高的程序性能。Doug Lea 大神为我们设计并实现了一款线程池工具,通过该工具就可以实现多线程的能力,并实现任务的高效执行与调度。优先在池子中创建一批线程链接,有需要访问线程时,直接到池子中去获取一个可用的链接,使用完了之后再归还到链接池中去。
线程池有5种状态,
RUNNING |
运行状态,该状态下线程池可以接受新的任务,也可以处理阻塞队列中的任务 |
SHUTDOWN |
待关闭状态,不再接受新的任务,继续处理阻塞队列中的任务 |
STOP |
停止状态,不接收新任务,也不处理阻塞队列中的任务,并且会尝试结束执行中的任务 |
TIDYING |
整理状态,此时任务都已经执行完毕,并且也没有工作线程 |
TERMINATED |
终止状态,此时线程池完全终止了,并完成了所有资源的释放 |
线程池需要线程去执行具体的任务的,所以在线程池中就封装了一个内部类 Worker 作为工作线程,每个 Worker 中都维持着一个 Thread。Ctl(3+29)表示线程池状态。
确定线程的合适,使用两个变量协作,核心线程数:corePoolSize 用来表示线程池中的核心线程的数量,也可以称为可闲置的线程数量
最大线程数:maximumPoolSize 用来表示线程池中最多能够创建的线程数量
线程创建交给了线程工厂 ThreadFactory 来完成。为线程池配备一个阻塞队列,用来临时缓存任务,这些任务将等待工作线程来执行。
核心线程跟创建的先后没有关系,而是跟工作线程的个数有关,如果当前工作线程的个数大于核心线程数,那么所有的线程都可能是“非核心线程”,都有被回收的可能。
一个线程执行完了一个任务后,会去阻塞队列里面取新的任务,在取到任务之前它就是一个闲置的线程。取任务的方法有两种,一种是通过 take() 方法一直阻塞直到取出任务,另一种是通过 poll(keepAliveTime,timeUnit) 方法在一定时间内取出任务或者超时,如果超时这个线程就会被回收,请注意核心线程一般不会被回收。
保证核心线程不会被回收呢,跟工作线程的个数有关,每一个线程在取任务的时候,线程池会比较当前的工作线程个数与核心线程数:
- 如果工作线程数小于当前的核心线程数,则使用第一种方法取任务,也就是没有超时回收,这时所有的工作线程都是“核心线程”,他们不会被回收;
- 如果大于核心线程数,则使用第二种方法取任务,一旦超时就回收,所以并没有绝对的核心线程,只要这个线程没有在存活时间内取到任务去执行就会被回收。
下次待续