线程池
2019-12-03 本文已影响0人
sizuoyi00
使用场景
执行时间短,需要处理的任务量比较大
优势:
1.重用线程,创建(用户空间->内核空间->内核线程)的销毁线程的开销,提高性能
2.提高响应速度,因为不需要创建
3.统一管理,对线程进行一些维护和管理,比如定时开始,周期执行,并发数控制等等
ThreadPoolExecutor
构造方法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
核心参数说明
-
corePoolSize
核心线程数,默认情况下核心线程会一直存活,即使处于闲置状态也不会受存keepAliveTime限制,除非将allowCoreThreadTimeOut设置为true。
提交任务时,当运行的线程数小于corePoolSize时,将创建一个新线程来处理请求,即使其他工作线程是空闲的。 -
maximumPoolSize
线程池所能容纳的最大线程数,如果有多于corePoolSize但小于maximumPoolSize的线程在运行,则只有在队列满时才会创建新线程。通过将corePoolSize和maximumPoolSize设置为相同的值,可以创建一个固定大小的线程池。 -
keepAliveTime
非核心线程的闲置超时时间,超过这个时间就会被回收。核心线程不受此控制,除非将allowCoreThreadTimeOut设置为true。 -
unit
指定keepAliveTime的单位,如TimeUnit.SECONDS。 -
workQueue
线程池中的任务队列,核心线程数满了后添加到任务队列。
常用的有三种队列:参考阻塞队列文章
LinkedBlockingDeque:指定大小代表定长队列,不指定相当于无界队列。
ArrayBlockingQueue:定长队列。
SynchronousQueue:无缓存队列,不存储元素。 -
threadFactory
线程创建工厂,提供创建新线程的功能,接口中只有newThread(Runnable r)方法 -
handler
拒绝策略,当线程池资源不足(核心线程数,任务队列,最大线程数都占满),采用拒绝策略。常见拒绝策略:
ThreadPoolExecutor.AbortPolicy:默认拒绝策略,丢弃任务并抛错处理
ThreadPoolExecutor.CallerRunsPolicy:由调用者线程执行该任务,如果执行器已经关闭则丢弃任务。
ThreadPoolExecutor.DiscardPolicy:丢弃任务,不执行任何操作。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任,重新尝试执行任务,如果执行器已经关闭则丢弃任务。
Executors创建线程池(禁用)
-
newSingleThreadExecutor
单线程线程池,无界队列,出现异常则重新创建一个代替。
new ThreadPoolExecutor(1, 1, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) -
newFixedThreadPool
固定大小线程池,无界队列,出现异常则会补充一个新线程。
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) -
newCachedThreadPool
可缓存线程池,SynchronousQueue无缓冲队列,如果没有可用的现有线程,将创建一个新的线程并将其添加到池中。已经60秒没有使用的线程将被终止并从缓存中删除。因此,长时间保持空闲的池不会消耗任何资源。
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())
阿里巴巴编程规范对于线程池的要求
线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
线程池状态分析
-
running:能够接收新任务,并且对已添加任务进行处理。
线程池初始化状态,线程一创建状态为running,初始线程数任务数为0 -
shutdown:不接收新任务,可以对已添加任务进行处理。
调用线程池shutdown()方法running->shutdown -
stop:不可以添加新任务,不处理已添加任务,正在处理的任务中止操作。
调用线程池shutdownNow()方法,running/shutdown->stop -
tidying:所有任务已终止,ctl记录的任务数量为0,当线程池状态为tidying时,会调用钩子函数terminated()。
shutdown状态阻塞队列为空,并且线程中执行的任务为空,转为tidying。
stop状态,线程中执行的任务为空,转为tidying。 -
termined:线程池彻底终止。
tidying状态,执行完terminated()后,转为terminated状态
任务数指的是线程数
执行规则:核心线程>阻塞队列>非核心线程>拒绝策略
-
如果任务队列为无界队列
线程数<核心线程数:创建核心线程
核心线程数<线程数<最大线程数:加入队列
线程数>最大线程数:加入队列
无界队列,创建核心线程->队列 -
如果任务队列为有界队列
线程数<核心线程数:创建核心线程
核心线程数<线程数<最大线程数:加入队列,队列满后,创建非核心线程
线程数>最大线程数:队列未满,加入队列;队列满后,拒绝策略
有界队列,创建核心线程->队列->创建非核心线程
任务完成后,闲置时间达到超时时间后,非核心线程会被清除 -
如果任务队列为无缓存队列SynchronousQueue
线程数<核心线程数:创建核心线程
核心线程数<线程数<最大线程数:创建非核心线程
线程数>最大线程数:拒绝策略
无缓存队列,创建核心线程->创建非核心线程
任务完成后,闲置时间达到超时时间后,非核心线程会被清除
非核心线程也可以执行阻塞队列的任务
实例demo可参考:
https://blog.csdn.net/qq_25806863/article/details/71126867