线程池
线程池
简介
缓存已创建的线程,以备执行后续的任务。
目的:
创建和销毁消除消耗系统的资源,通过缓存已创建的线程,避免频繁的创建线程,从而减少系统的消耗。
与线程池有关的类和接口
Executor:底层接口,定义了execute(),表示执行传进来的任务。ExecutorService:继承自Executor,声明了一些常用方法:submit,invokeAll,invokeAny,shutDown。AbstractExecutorService:实现ExecutorService接口,基本实现ExecutorService中的方法。ThreadPoolExecutor:继承自AbstractExecutorService。execute():向线程池提交一个任务,由线程池执行。submit():向线程池提交任务,可以返回任务执行的结果。shutdown()关闭线程。shutdownNow():立即关闭线程池。
线程池的参数
corePoolSize:核心池的大小。创建线程池默认没有线程,得到任务到达时才创建线程。当线程数目到达corePoolSize时,会把后续的任务放入缓存队列中。maximumPoolSize:线程池的最大线程数。表示线程池中所能容纳的最大的线程数量。keepAliveTime:表示线程在没有执行任务,存活多久后被终止。当线程池中的线程大于corePoolSize时,会对超过数量的线程统计空闲时间,然后超过keepAliveTime的线程会被终止,直到线程池中的线程数量不超过corePoolSize。unit:超时时间单位。workQueue:阻塞队列,用来存储等待执行的任务。threadFactory:线程工厂,创建一个新线程时使用的工厂,可以设定线程名,是否为守护线程。handler:拒绝策略,当等待队列中的任务达到最大限制,并且线程池中线程数达到最大限制时,若有新的任务到达,则采取的拒绝策略。
线程池的状态
RUNNING = 0:线程池创建完后初始化。SHUTDOWN = 1:调用shutdown()方法,线程池不再接受新的任务,等待现有任务执行完。STOP = 2:调用shutdownNow()方法,线程池不接受新的任务,并且终止正在执行的任务。TERMINATED = 3:线程池处于SHUTDOWN或STOP状态,并且工作线程已被销毁,任务队列已被清空,则进入TERMINATED状态。
线程池执行流程
流程:
- 如果当前线程池中的线程数目 小于
< corePoolSize。则对于每个新任务,都会创建一个线程去执行这个任务。 - 如果当前线程池中的线程数目 大于等于
>= corePoolSize。对于每个新任务,会将其添加到任务队列中。若添加成功,则任务由空闲的线程主动将其从队列中移除后执行。若添加失败(任务队列已满),则尝试创建新的线程执行。 - 若当前线程池中的线程数目到达
maximumPoolSize,则对于新任务采取拒绝策略。 - 如果线程池中的数量大于
corePoolSize时,如果某个线程空闲时间超过keepAliveTime,线程会被终止,直到线程池中的线程数目不超过corePoolSize。 - 如果为核心线程池中的线程设置存活时间,则当核心线程池中的线程空闲时间超过
keepAliveTime,则该线程也会被终止。
线程池的初始化
- 默认情况下,创建线程池后,线程池中没有线程。需要在提交任务后才创建线程。
- 可以通过两个方法在创建线程池后创建线程:
prestartCoreThread():初始化一个线程。prestartAllCoreThread():初始化所有核心线程。
任务队列和排队策略
workQueue:用来存放等待执行的任务。类型为BlockingQueue<Runnable>。
阻塞队列
分类:
操作
方法
- 插入数据:
offer():添加数据成功返回true,添加失败返回false。(若没有设置超时时间,则直接返回;若设置超时时间,则等待指定的超时时间,超时时间过期后返回false)put():添加数据成功则直接返回,添加失败会被一直阻塞。
- 获取数据:
poll():若队列有元素,则获取队首元素;否则直接返回null。(若设置超时时间,则未成功获取元素时阻塞等待,直到超时返回null或成功获取元素)take():若队列非空,则直接返回队列首部元素;否则一直阻塞,直到成功获取元素或被中断。
类型:
ArrayBlockingQueue:基于 数组 的FIFO队列,创建时必须指定大小,内部使用定长数组缓存数据。读写数据同用同一个锁对象(可以使用锁分离实现生产者和消费者的并行,但ArrayBlockingQueue的读写为轻量级,使用锁分离只会增加复杂度。),可以采用公平锁或非公平锁。LinkedBlockingQueue:基于 链表 的FIFO队列,可以不指定大小,则大小为Integer.MAX_VALUE。对于生产者和消费者采用独立的锁进行同步,生产者和消费者可以并发操作队列中的数据。(若没有设置初始容量可能由于线程过多导致内存耗尽)synchronousQueue:一种没有缓冲的等待队列。不保存提交的任务,而是直接创建一个新线程执行新的任务。- 若为 公平模式 :采用公平锁,并使用FIFO队列阻塞生产者和消费者。
- 若为 非公平模式 :采用非公平锁,使用LIFO队列管理阻塞的生产者和消费者。
DelayQueue:队列中元素只有在指定的延迟时间到了才能获取到。生产者线程不会被阻塞,消费者线程在队列为空或者没有元素到期时会被阻塞。PriorityBlockingQueue:基于优先级的阻塞队列。不会阻塞生产者。当队列中没有元素时,阻塞消费者。采用公平锁。
拒绝策略
情景
当线程池中的线程达到 maximumPoolSize ,并且任务队列已满,此时对于新来的任务采取拒绝策略进行处理。
分类
AbortPolicy:抛弃任务,并抛出异常。DiscardPolicy:直接抛弃任务,但不抛出异常。DiscardOldPolicy:抛弃任务队列中最前的任务(最老的任务),然后尝试执行新任务。CallerRunPolicy:由调用线程处理任务。
线程池的关闭
shutdown():不会立即终止线程池,而是不再接受新的任务,并且等待所有任务缓存队列中的任务都执行完后才终止。shutdownNow():立即终止线程池,并打断正在执行的任务,清空任务队列,返回尚未执行的任务。
线程池容量的动态调整
setCorePoolSize():设置核心池的大小。setMaximumPoolSize():设置线程池最大能创建线程的数目。
配置线程池的参数
根据任务的类型进行配置。
- CPU密集型任务:
corePoolSize设置为CPU核心数+1; - IO密集型任务:
corePoolSize设置为2*CPU核心数。
Executors 创建四种线程池
提供一系列工厂方法来创建线程池。
newCachedThreadPool:一个可缓存线程池,通过execute重用已经构建的线程。若没有可用线程,则创建新线程并添加到线程池中。终止超时未使用(60s)的线程。newFixedThreadPool:一个固定线程数量的线程池,控制线程的最大并发数,超过的线程在队列中等待。newScheduledThreadPool:一个定长的线程池,支持定时以及周期性任务执行。newSingleThreadExecutor:一个单线程的线程池,使用一个工作线程,保证任务按照FIFO,LIFO顺序执行。
newCachedThreadPool
newFixedThreadPool
newScheduledThreadPool
newSingleThreadExecutor
- 单例线程池,任意时刻只有一个线程。
本文来自博客园,作者:战五渣渣渣渣渣,转载请注明原文链接:https://www.cnblogs.com/truestoriesavici01/p/13662895.html

浙公网安备 33010602011771号