Thread.ThreadPool

线程池的好处:数组

第一:下降资源消耗。经过重复利用已建立的线程下降线程建立和销毁形成的消耗。缓存

第二:提升响应速度。当任务到达时,任务能够不须要的等到线程建立就能当即执行。服务器

第三:提升线程的可管理性。线程是稀缺资源,若是无限制的建立,不只会消耗系统资源,还会下降系统的稳定性,使用线程池能够进行统一的分配,调优和监控。可是要作到合理的利用线程池,必须对其原理了如指掌。并发

线程池的建立

咱们能够经过ThreadPoolExecutor来建立一个线程池。异步

1 new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
2 keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

建立一个线程池须要输入几个参数:spa

  • corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会建立一个线程来执行任务,即便其余空闲的基本线程可以执行新任务也会建立线程,等到须要执行的任务数大于线程池基本大小时就再也不建立。若是调用了线程池的prestartAllCoreThreads方法,线程池会提早建立并启动全部基本线程。
  • runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。能够选择如下几个阻塞队列。
  1. ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
  2. LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量一般要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
  3. SynchronousQueue:一个不存储元素的阻塞队列。每一个插入操做必须等到另外一个线程调用移除操做,不然插入操做一直处于阻塞状态,吞吐量一般要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
  4. PriorityBlockingQueue:一个具备优先级得无限阻塞队列。
  • maximumPoolSize(线程池最大大小):线程池容许建立的最大线程数。若是队列满了,而且已建立的线程数小于最大线程数,则线程池会再建立新的线程执行任务。值得注意的是若是使用了无界的任务队列这个参数就没什么效果。
  • ThreadFactory:用于设置建立线程的工厂,能够经过线程工厂给每一个建立出来的线程设置更有意义的名字,Debug和定位问题时很是又帮助。

RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采起一种策略处理提交的新任务。这个策略默认状况下是AbortPolicy,表示没法处理新任务时抛出异常。如下是JDK1.5提供的四种策略。n  AbortPolicy:直接抛出异常。线程

  1. CallerRunsPolicy:只用调用者所在线程来运行任务。
  2. DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
  3. DiscardPolicy:不处理,丢弃掉。
  4. 固然也能够根据应用场景须要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
  • keepAliveTime(线程活动保持时间):线程池的工做线程空闲后,保持存活的时间。因此若是任务不少,而且每一个任务执行的时间比较短,能够调大这个时间,提升线程的利用率。
  • TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

线程池的executor,submit区别在于,execute不用返回结果,submit返回furture包装的结果值rest

线程池的关闭

shutdown:shutdown的原理是只是将线程池的状态设置成SHUTDOWN状态,而后中断全部没有正在执行任务的线程日志

shutdownNow:shutdownNow的原理是遍历线程池中的工做线程,而后逐个调用线程的interrupt方法来中断线程,因此没法响应中断的任务可能永远没法终止。shutdownNow会首先将线程池的状态设置成STOP,而后尝试中止全部的正在执行或暂停任务的线程,并返回等待执行任务的列表。code

只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当全部的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于咱们应该调用哪种方法来关闭线程池,应该由提交到线程池的任务特性决定,一般调用shutdown来关闭线程池,若是任务不必定要执行完,则能够调用shutdownNow。

3.    线程池的分析

流程分析:线程池的主要工做流程以下图:

从上图咱们能够看出,当提交一个新任务到线程池时,线程池的处理流程以下:

  1. 首先线程池判断基本线程池是否已满?没满,建立一个工做线程来执行任务。满了,则进入下个流程。
  2. 其次线程池判断工做队列是否已满?没满,则将新提交的任务存储在工做队列里。满了,则进入下个流程。
  3. 最后线程池判断整个线程池是否已满?没满,则建立一个新的工做线程来执行任务,满了,则交给饱和策略来处理这个任务。

 

一: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)。

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息