一、为什么使用线程池
- 重用线程池中的使用,减少创建线和销毁程的的资源消耗和提高性能。
- 可以对线程进行管理与维护
二、线程池的创建
线程池的创建可以使用Executors类中的方法创建,可以参考常用的四种线程池的创建,下面来看J.U.C包下的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,
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) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
/**第四种创建方式*/
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
corePoolSize:核心线程池的大小,线程池创建完成之后,线程池中默认没有任何线程。只有在有任务到达时才会创建一个线程去执行,直到corePoolSize。
maximumPoolSize:线程池中允许最大的线程数。
keepAliveTime:空闲线程等待新任务的最大存活时间。
unit:keepAliveTime的时间单位,比如TimeUnit.MILLISECONDS;TimeUnit.SECONDS; TimeUnit.MINUTES; TimeUnit.HOURS;
workQueue:阻塞队列,当线程池中的线程大于corePoolSize时,新建的任务将会进入阻塞队列等待执行,可以查看常用的阻塞队列。
threadFactory:创建线程的工厂
handler:拒绝任务的处理策略。
拒绝策略:
- AbortPolicy:直接丢弃任务并抛出RejectedExecutionException。
- CallerRunsPolicy:只要线程池未关闭,就会执行调用者线程中丢弃的任务,这样会降低线程的性能。
- DiscardOldestPolicy:丢弃任务队列中时间最长的任务然后尝试提交当前的任务。
- DiscardPolicy:丢弃任务,不做任何处理。
线程池处理任务的规则:
- 当前线程池中线程的数目<corePoolSize,则每来一个任务,就会创建一个线程来执行
- 当前线程池中线程的数目>=corePoolSize,当有任务时,则会尝试添加到阻塞队列中,若添加成功,则会等待空闲线程来将其执行,若添加失败(一般是阻塞队列已满),则会创建新的线程去执行,当然前提是不能maximumPoolSize的数量。
- 若当前线程池中的线程数量>maximumPoolSize,则执行任务拒绝策略处理
- 当前线程池中的线程数量?corePoolSize时,若某个空闲线程超过keepAliveTime时间,则会被丢弃,直到线程数量小于corePoolSize。一般情况下,核心线程不会被丢弃。
线程池中任务到达的执行流程:
线程池中的状态:
- RUNNING:接收新的任务,执行任务队列中的任务。
- SHUTDOWN:不接收新任务,但是执行任务队列中的任务。
- STOP:不接收新任务,也不执行任务队列中的任务,并打断正在执行的任务。
- TIDYING:终止所有的任务,工作线程的数量为0,并且会执行terminated()回调函数。
- TERMINATED:terminated()方法已执行完毕。
状态转换:
RUNNING -> SHUTDOWN: 在调用shutDown()方法时。
(RUNNING or SHUTDOWN) -> STOP:在调用shutDownNow()方法时。
SHUTDOWN -> TIDYING:线程池和阻塞队列都为空。
STOP -> TIDYING :线程池为空。
TIDYING -> TERMINATED :terminated()方法执行完毕时。