线程池的好处:数组
第一:下降资源消耗。经过重复利用已建立的线程下降线程建立和销毁形成的消耗。缓存
第二:提升响应速度。当任务到达时,任务能够不须要的等到线程建立就能当即执行。服务器
第三:提升线程的可管理性。线程是稀缺资源,若是无限制的建立,不只会消耗系统资源,还会下降系统的稳定性,使用线程池能够进行统一的分配,调优和监控。可是要作到合理的利用线程池,必须对其原理了如指掌。并发
咱们能够经过ThreadPoolExecutor来建立一个线程池。异步
1 |
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, |
2 |
keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler); |
建立一个线程池须要输入几个参数:spa
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采起一种策略处理提交的新任务。这个策略默认状况下是AbortPolicy,表示没法处理新任务时抛出异常。如下是JDK1.5提供的四种策略。n AbortPolicy:直接抛出异常。线程
线程池的executor,submit区别在于,execute不用返回结果,submit返回furture包装的结果值rest
shutdown:shutdown的原理是只是将线程池的状态设置成SHUTDOWN状态,而后中断全部没有正在执行任务的线程日志
shutdownNow:shutdownNow的原理是遍历线程池中的工做线程,而后逐个调用线程的interrupt方法来中断线程,因此没法响应中断的任务可能永远没法终止。shutdownNow会首先将线程池的状态设置成STOP,而后尝试中止全部的正在执行或暂停任务的线程,并返回等待执行任务的列表。code
只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当全部的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于咱们应该调用哪种方法来关闭线程池,应该由提交到线程池的任务特性决定,一般调用shutdown来关闭线程池,若是任务不必定要执行完,则能够调用shutdownNow。
流程分析:线程池的主要工做流程以下图:
从上图咱们能够看出,当提交一个新任务到线程池时,线程池的处理流程以下:
一:newCachedThreadPool-可变尺寸的线程池(缓存线程池)
(1)缓存型池子,先查看池中有没有之前创建的线程,若是有,就reuse(重用),若是没有,就创建一个新的线程加入池中;
(2)缓存型池子,一般用于执行一些生存周期很短的异步型任务;所以一些面向链接的daemon型server中用得很少;
(3)能reuse(重用)的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池;
(4)注意,放入CachedThreadPool的线程没必要担忧其结束,超过TIMEOUT不活动,其会自动被终止。
二:newFixedThreadPool-固定大小的线程池
(1)newFixedThreadPool与cacheThreadPool差很少,也是能reuse就用,但不能随时建新的线程;
(2)其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时若是有新的线程要创建,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子;
(3)和cacheThreadPool不一样,FixedThreadPool没有IDLE机制(可能也有,但既然文档没提,确定很是长,相似依赖上层的TCP或UDP IDLE机制之类的),因此FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器;
(4)从方法的源代码看,cache池和fixed池调用的是同一个底层池,只不过参数不一样:
fixed池线程数固定,而且是0秒IDLE(无IDLE);
cache池线程数支持0-Integer.MAX_VALUE(显然彻底没考虑主机的资源承受能力),60秒IDLE。
三:ScheduledThreadPool-调度线程池
(1)调度型线程池;
(2)这个池子里的线程能够按schedule依次delay执行,或周期执行。
四:SingleThreadExecutor-单例线程池
(1)单例线程,任意时间池中只能有一个线程; (2)用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)。