线程池
创建线程池
执行流程
1、当线程池中线程数小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
2、当线程池中线程数达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 。
3、当workQueue已满,且maximumPoolSize > corePoolSize时,新提交任务会创建新线程执行任务。
4、当workQueue已满,且提交任务数超过maximumPoolSize,任务由RejectedExecutionHandler处理。
5、当线程池中线程数超过corePoolSize,且超过这部分的空闲时间达到keepAliveTime时,回收这些线程。
6、当设置 allowCoreThreadTimeOut(true)时,线程池中corePoolSize范围内的线程空闲时间达到keepAliveTime也将回收。
参数分析
-
corePoolSize:核心线程池数量 在线程数少于核心数量时,有新任务进来就新建一个线程,即使有的线程没事干 等超出核心数量后,就不会新建线程了,空闲的线程就得去任务队列里取任务执行了
-
maximumPoolSize:最大线程数量 包括核心线程池数量 + 核心以外的数量 如果任务队列满了,并且池中线程数小于最大线程数,会再创建新的线程执行任务
-
keepAliveTime:核心池以外的线程存活时间,即没有任务的外包的存活时间 如果给线程池设置 allowCoreThreadTimeOut(true),则核心线程在空闲时头上也会响起死亡的倒计时 如果任务是多而容易执行的,可以调大这个参数,那样线程就可以在存活的时间里有更大可能接受新任务
-
workQueue:保存待执行任务的阻塞队列
- ArrayBlockingQueue:基于数组、有界,按 FIFO(先进先出)原则对元素进行排序
- LinkedBlockingQueue:基于链表,无界,按FIFO (先进先出) 排序元素 吞吐量通常要高于 ArrayBlockingQueue Executors.newFixedThreadPool() 使用了这个队列
- SynchronousQueue:不存储元素的阻塞队列 每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态 吞吐量通常要高于 LinkedBlockingQueue Executors.newCachedThreadPool使用了这个队列
- PriorityBlockingQueue:具有优先级的、无限阻塞队列
如果是要求高吞吐量的,可以使用
SynchronousQueue队列;如果对执行顺序有要求,可以使用PriorityBlockingQueue;如果最大积攒的待做任务有上限,可以使用LinkedBlockingQueue。 -
threadFactory:每个线程创建的地方 可以给线程起个好听的名字,设置个优先级啥的
-
handler:饱和策略,大家都很忙,咋办呢,有四种策略 CallerRunsPolicy:只要线程池没关闭,就直接用调用者所在线程来运行任务 AbortPolicy:直接抛出 RejectedExecutionException 异常 DiscardPolicy:悄悄把任务放生,不做了 DiscardOldestPolicy:把队列里待最久的那个任务扔了,然后再调用 execute() 试试看能行不 我们也可以实现自己的 RejectedExecutionHandler 接口自定义策略,比如如记录日志什么的
提交线程池
ExecutorService 提供了两种提交任务的方法:
execute():提交不需要返回值的任务 Runnablesubmit():提交需要返回值的任务 Callable
关闭线程池
shutdown() 只结束未执行的任务;shutdownNow() 结束全部。
shutdown() 状态stop;shutdownNow() 状态shutdown。
shutDown()
当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态。
此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常。
但是,此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。
shutdownNow()
线程池的状态立刻变成STOP状态
调用线程 interrupt方法并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务。 它试图终止线程的方法是通过调用**Thread.interrupt()**方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt()方法是无法中断当前的线程的。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。
自带线程池
CachedThreadPool 用于并发执行大量短期的小任务,或者是负载较轻的服务器。
FixedThreadPool 用于负载比较重的服务器,为了资源的合理利用,需要限制当前线程数量。
SingleThreadExecutor 用于串行执行任务的场景,每个任务必须按顺序执行,不需要并发执行。
ScheduledThreadPoolExecutor 用于需要多个后台线程执行周期任务,同时需要限制线程数量的场景。