线程池

194 阅读4分钟

线程池

创建线程池

image.png

执行流程

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 提供了两种提交任务的方法:

  1. execute():提交不需要返回值的任务 Runnable
  2. submit():提交需要返回值的任务 Callable

关闭线程池

shutdown() 只结束未执行的任务;shutdownNow() 结束全部。

shutdown() 状态stop;shutdownNow() 状态shutdown。

shutDown()

当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态。

此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常

但是,此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。

shutdownNow()

线程池的状态立刻变成STOP状态

调用线程 interrupt方法并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务。 它试图终止线程的方法是通过调用**Thread.interrupt()**方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt()方法是无法中断当前的线程的。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。

自带线程池

CachedThreadPool 用于并发执行大量短期的小任务,或者是负载较轻的服务器。
FixedThreadPool 用于负载比较重的服务器,为了资源的合理利用,需要限制当前线程数量。
SingleThreadExecutor 用于串行执行任务的场景,每个任务必须按顺序执行,不需要并发执行。
ScheduledThreadPoolExecutor 用于需要多个后台线程执行周期任务,同时需要限制线程数量的场景。