1、线程池的优势:
- 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
- 能有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
- 能对线程进行简单的管理。并提供定时执行以及指定间隔循环执行等功能。
ThreadPoolExecutor的构造方法
可以通过ThreadPoolExecutor来创建一个线程池,ThreadPoolExecutor类一共有4个构造方法。其中,拥有最多参数的构造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数说明:
- corePoolSize: 线程池核心线程数。默认情况下,核心线程会在线程池中一直存活,即使他们处于闲置状态。如果当前运行的线程数少于
corePoolSize
,则创建新线程来处理任务;如果当前运行的线程数等于或多于corePoolSize
,则不再创建新的线程。 - maxmumPoolSize: 线程池允许创建的最大线程数。如果任务队列满了并且线程数小于
maximumPoolSize
时,则线程池仍然会创建新的线程来处理任务。 - keepAliveTime: 非核心线程闲置的超时时间。超过这个时间,非核心线程会被回收。如果
allowCoreThreadTimeout
设置为true,核心线程也会被回收。 - TimeUnit:
keepAliveTime
参数的时间单位。这是一个枚举,有Days(天)、HOURS(小时)、MINUTES(分钟)、MILLISECONDS(毫秒)、SECONDS(秒)等。 - workQueue: 任务队列。如果当前线程数大于
corePoolSize
,则将任务添加到此任务队列中。该任务队列是BlockingQueue类型的,也就是阻塞队列。存储在这里的任务是由ThreadPoolExecutor
的execute
方法提交来的。 - threadFactory: 线程工厂。为线程池提供创建新线程的功能,一般情况下无须设置该参数。
- RejectedExecutionHandler: 饱和策略。这是当前任务队列和线程池都满了时所采取的应对策略,默认是AbordPolicy,表示无法处理新任务,并抛出RejectedExecutionException异常。
RejectedExecutionHandler:饱和策略(共4种):
1.AbordPolicy:无法处理新任务,并抛出RejectedExecutionException异常。
2.CallerRunsPolicy:用调用者所在的线程来处理任务。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
3.DiscardPolicy:不能执行的任务,并将该任务删除。
4.DiscardOldestPolicy:丢弃队列最近的任务,并执行当前的任务。
线程池的原理,当提交一个新的任务到线程池时,线程池的处理流程如下:
2、执行
ThreadPoolExecutor有两个方法可以供我们执行,分别是submit()和execute(),我们先来看看这两个方法到底有什么差异。
execute()方法源码:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//获得当前线程的生命周期对应的二进制状态码
int c = ctl.get();
//判断当前线程数量是否小于核心线程数量,如果小于就直接创建核心 线程执行任务,创建成功直接跳出,失败则接着往下走.
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//判断线程池是否为RUNNING状态,并且将任务添加至队列中.
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//审核下线程池的状态,如果不是RUNNING状态,直接移除队列中
if (! isRunning(recheck) && remove(command))
reject(command);
//如果当前线程数量为0,则单独创建线程,而不指定任务.
else if (workerCountOf(recheck) == 0)