线程池是什么?为什么要使用线程池?
线程池用来管理和控制线程数量。
线程是种昂贵的资源,线程的创建、启动、销毁、调度都是需要额外的开销的。
线程池的优势:
- 线程的复用。
- 线程的管理。
- 线程数量的控制。
第一:降低资源消耗.通过重复利用自己创建的线程降低线程创建和销毁造成的消耗.
第二: 提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.
第三: 提高线程的可管理性.线程是稀缺资源,如果无限的创建,不仅会消耗资源,还会较低系统的稳定性,使用线程池可以进行统一分配,调优和监控。
java的框架实现:
Executors顾名思义,和Collections相似,是一个工具类。
Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的newScheduledThreadPool、newFixedThreadPool、newCachedThreadPool方法其实也只是ThreadPoolExecutor的构造函数参数不同而已。通过传入不同的参数,就可以构造出适用于不同应用场景下的线程池。
Executors使用有风险,不建议使用。
线程池的七个参数
我们来看看这几个参数的含义:
-
corePoolSize: 线程池中的常驻核心线程数。
(1)在创建了线程池后,当有请求任务来之后,就会安排池中的线程去执行请求任务,近似理解为今日当值线程
(2)当线程池中的线程数目达到corePoolSize后,就会把到达的任务放入到缓存队列当中. -
maximumPoolSize: 线程池能够容纳同时执行的最大线程数,此值大于等于1
-
keepAliveTime: 多余的空闲线程存活时间,当空间时间达到keepAliveTime
值时,多余的线程会被销毁直到只剩下corePoolSize 个线程为止。
(1)默认情况下:只有当线程池中的线程数大于corePoolSize时keepAliveTime才会起作用,直到线程中的线程数不大于corepoolSIze。 -
unit:keepAliveTime的单位。
-
workQueue:任务队列,被提交但尚未被执行的任务。
-
threadFactory:表示生成线程池中工作线程的线程工厂,用户创建新线程,自定义线程名字。
-
handler:拒绝策略,表示当线程队列满了并且工作线程大于等于线程池的最大显示 数(maxnumPoolSize)时如何来拒绝。
(1) 有四种拒绝策略:
①AbortPolicy 直接抛出异常(默认)
②DiscardPolicy丢弃当前被拒绝的任务,不抛出异常。(运行丢失的情况可以考虑)
③CallerRunPolicy:"调用者运行"一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是该任务被线程池拒绝,由调用execute方法的线程执行该任务。
④DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交。
线程池的状态
线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated
RUNNING
(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。
(2) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!
2、 SHUTDOWN
(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。
(2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。
3、STOP
(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
(2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。
4、TIDYING
(1) 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
(2) 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。
当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。
5、 TERMINATED
(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。
(2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。
线程池底层的工作原理
线程的顺序不能乱,是核心线程–>队列–>最大线程–>拒绝策略。
这里有几个个小问题:
- 如果是Executors创建的FixedThreadPool、CachedThreadPool(队列长度为Integer.MAX_VALUE)顺序会改变吗?
- 程序刚刚启动核心线程会被创建吗?
后面的博客给答案