使用线程池的优点:
- 通过线程池机制,实现线程复用,避免频繁地进行 Thread 线程对象的创建和销毁,提高了在执行大量任务时的性能,也避免了之前哪种对于每个任务都需要显式创建一个 Thread 线程对象来执行的问题。
- 通过设置内部的 Thread 线程池和任务等待队列的大小,可以根据当前系统资源情况,灵活控制系统的最大资源开销,避免创建过多线程或者在任务等待队列存放过多任务,造成系统资源的过多消耗。
- Executor 线程池框架也提供了审计功能,即提供了任务执行情况的统计功能,如当前的 Executor 线程池实例一共执行了多少个任务。
Executor 接口
包含一个 execute 方法,表示提交任务给线程池执行。
public interface Executor {
//提交一个任务到线程池异步执行
void execute(Runnable command);
}
ExecutorService 接口
继承于 Executor 接口,增加了线程池的关闭、任务执行结果的返回功能。
public interface Executor {
...
void shutdown();
Future<?> submit(Runnable task);
...
}
Future 类提供异步获取任务的执行结果的功能,故可以在应用程序中获取此次提交任务的执行结果。
ThreadPoolExecutor 线程池
ThreadPoolExecutor 是 Executor 线程池框架的具体实现,是我们在应用程序种定义线程池时最常用的一个类,是 Executor 线程池框架提供给应用程序使用的一个核心类。
对于 ThreadPoolExecutor 构造函数,有以下参数:
- corePoolSize:线程池中核心线程的数量
- maximumPoolSize:线程池的最大值,线程池最多可以创建的线程数
- keepAliveTime:如果线程池中的线程数量超过了 corePoolSize,且存在空闲线程,则空闲时间超过 keepAliveTime 时,线程就会被销毁回收。
- workQueue:线程池中没有空闲线程时,新提交的任务进入该任务等待队列。
- threadFactory:线程池的线程创建工厂类。
- RejectedExecutionHandler:任务拒绝策略。
任务的提交
使用 execute 或者 submit 方法来提交任务,execute 方法没有返回值,submit 方法使用 Future 对象作为返回值,可以通过该对象来跟踪这个任务的执行和获取执行结果。
任务提交流程
-
如果线程池中的线程数少于corePoolSize,则创建一个新线程来执行该任务
-
若线程数达到了corePoolSIze,则将任务放到 workQueue 中。线程池中存在空闲线程时,空闲线程会从任务队列中取出任务并处理
-
若任务等待队列 workQueue 也满了时,如果线程池当前工作线程数小于 maximumPoolSize,则创建新线程执行该任务。
-
否则调用 reject 方法,根据具体的任务拒绝策略处理该任务。任务拒绝策略默认为 AbortPolicy,即在 execute 方法抛异常。
- 任务拒绝策略:AbortPolicy:抛 Abort 异常
- CallerRunsPolicy:在主线程直接执行该任务
- DiscardPolicy:默默丢弃该任务
- DiscardOldestPolicy:移除任务等待队列队头的任务,将该任务添加到队列中