线程池必备知识点

一、为什么使用线程池

1.通过重复利用已经创建的线程降低资源消耗。

2.任务可以不需要等到线程创建就可以提高响应速度。

3.Java的线程池可以对线程资源进行统一分配,管理。

二、线程池的核心参数

1.corePoolSize(线程池的基本大小)

(1)提交一个任务到线程池时,线程池会创建一个新的线程来执行任务。注意:即使有空闲的基本线程能执行该任务,也会创建新的线程。

(2)如果线程池中的线程数已经大于或等于corePoolSize,则不会创建新的线程。

2.maximumPoolSize(线程池的最大数量):线程池允许创建的最大线程数。

(1)阻塞队列已满,线程数小于maximumPoolSize便可以创建新的线程执行任务。

(2)如果使用无界的阻塞队列,该参数没有什么效果。

3.workQueue(工作队列):用于保存等待执行的任务的阻塞队列。

(1)ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO(先进先出)原则对任务进行排序。使用该队列,线程池中能创建的最大线程数为maximumPoolSize。

(2)LinkedBlockingQueue:基于链表结构的无界阻塞队列,按FIFO(先进先出)原则对任务进行排序,吞吐量高于ArrayBlockingQueue。使用该队列,线程池中能创建的最大线程数为corePoolSize。静态工厂方法 Executor.newFixedThreadPool()使用了这个队列。

(3)SynchronousQueue:一个不存储元素的阻塞队列。添加任务的操作必须等到另一个线程的移除操作,否则添加操作一直处于阻塞状态。静态工厂方法 Executor.newCachedThreadPool()使用了这个队列。(SynchronousQueue是不存储任务的,新的任务要么立即被已有线程执行,要么创建新的线程执行。)

(4)PriorityBlokingQueue:一个支持优先级的无界阻塞队列。使用该队列,线程池中能创建的最大线程数为corePoolSize。

5.keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。如果任务多而且任务的执行时间比较短,可以调大keepAliveTime,提高线程的利用率。

6.unit(线程活动保持时间的单位):可选单位有DAYS、HOURS、MINUTES、毫秒、微秒、纳秒。

7.handler(饱和策略,或者又称拒绝策略):当队列和线程池都满了,即线程池饱和了,必须采取一种策略处理提交的新任务。

  • AbortPolicy:无法处理新任务时,直接抛出异常,这是默认策略。
  • CallerRunsPolicy:用调用者所在的线程来执行任务。
  • DiscardOldestPolicy:丢弃阻塞队列中最靠前的一个任务,并执行当前任务。
  • DiscardPolicy:直接丢弃任务。

threadFactory:构建线程的工厂类

三、线程池的五种运行状态

RUNNING :  该状态的线程池既能接受新提交的任务,又能处理阻塞队列中任务。

SHUTDOWN: 该状态的线程池不能接收新提交的任务,但是能处理阻塞队列中的任务。(政府服务大厅不在允许群众拿号了,处理完手头的和排队的政务就下班。)

  • 处于 RUNNING 状态时,调用 shutdown()方法会使线程池进入到该状态。
  • 注意:finalize() 方法在执行过程中也会隐式调用shutdown()方法。

STOP:  该状态的线程池不接受新提交的任务,也不处理在阻塞队列中的任务,还会中断正在执行的任务。(政府服务大厅不再进行服务了,拿号、排队、以及手头工作都停止了。)

  • 在线程池处于 RUNNING 或 SHUTDOWN 状态时,调用 shutdownNow() 方法会使线程池进入到该状态;

TIDYING:  如果所有的任务都已终止,workerCount (有效线程数)=0 。

  • 线程池进入该状态后会调用 terminated() 钩子方法进入TERMINATED 状态。

TERMINATED: 在terminated()钩子方法执行完后进入该状态,默认terminated()钩子方法中什么也没有做。

四、线程池的关闭(shutdown或者shutdownNow方法)

    • shutdown方法将线程池的状态设置为SHUTDOWN状态,只会中断空闲的工作线程。
    • shutdownNow方法将线程池的状态设置为STOP状态,会中断所有工作线程,不管工作线程是否空闲。
    • 调用两者中任何一种方法,都会使isShutdown方法的返回值为true;线程池中所有的任务都关闭后,isTerminated方法的返回值为true。
    • 通常使用shutdown方法关闭线程池,如果不要求任务一定要执行完,则可以调用shutdownNow方法。

五、线程池的工作流程

一个新的任务到线程池时,线程池的处理流程如下:

  1. 如果当前运行的线程少于corePoolSize,则创建新的工作线程来执行任务(执行这一步骤需要获取全局锁)。
  2. 如果当前运行的线程大于或等于corePoolSize,而且BlockingQueue未满,则将任务加入到BlockingQueue中。
  3. 如果BlockingQueue已满,而且当前运行的线程小于maximumPoolSize,则创建新的工作线程来执行任务(执行这一步骤需要获取全局锁)。
  4. 如果当前运行的线程大于或等于maximumPoolSize,任务将被拒绝,并调用RejectExecutionHandler.rejectExecution()方法。即调用饱和策略对任务进行处理。

六、四种线程池

1.newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务, 保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
适用场景:任务少 ,并且不需要并发执行

2.newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.
线程没有任务要执行时,便处于空闲状态,处于空闲状态的线程并不会被立即销毁(会被缓存住),只有当空闲时间超出一段时间(默认为60s)后,线程池才会销毁该线程(相当于清除过时的缓存)。新任务到达后,线程池首先会让被缓存住的线程(空闲状态)去执行任务,如果没有可用线程(无空闲线程),便会创建新的线程。

 

 核心线程为0 ,最大线程为无限大,说明,如果没有空闲的线程,而任务一直在提交,那么会一直创建新线程

适用场景:处理任务速度 > 提交任务速度,耗时少的任务(避免无限新增线程)
newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行

参考资料:https://mp.weixin.qq.com/s/ZexCxxg5HmZdNNnKbPjrkQ

posted @ 2021-04-08 10:49  我是张某某  阅读(152)  评论(0)    收藏  举报