ThreadPoolExecutor线程池
使用普通线程会带来一些问题,如匿名Runnable无法进行管理,多次执行需要new多次对象;而使用线程池,不仅可以控制并发数、还可以重复利用存在的线程,减少系统的开销。
构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {}
代码示例:
public static void main(String[] args) {
//创建核心线程为3/最大线程为5的/空闲时间0/单位秒/阻塞队列容量1/丢弃任务
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(3, 5, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(1),
new ThreadPoolExecutor.DiscardPolicy());
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {}
});
threadPoolExecutor.shutdown(); //关闭线程池
}
核心参数
corePoolSize:核心线程数。即线程池中长时间稳定存活的线程数;
maxPoolSize:最大线程数。即线程池中最大可包含的线程数;
keepAliveTime:空闲线程存活时间。即非核心线程的存活时间;
TimeUnit:时间单位。即TimeUnit.SECONDS秒、MILLISECONDS毫秒、微秒MICROSECONDS和毫微秒NANOSECONDS;
workQueue 任务阻塞队列
有界队列:ArrayBlockingQueue,按 FIFO(先进先出)原则对元素进行排序。
无界队列:LinkedBlockingQueue,容量Integer.MAX_VALUE,无限添加任务直致OOM。
直接交换:SynchronousQueue,不存储元素。需等线程调用移除操作,否则处于阻塞状态。
PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
RejectedExecutionHandler 拒绝策略
线程池和阻塞队列都满了时,所采取一种策略处理提交的新任务。
AbortPolicy:(默认策略)丢弃任务,并抛出RejectedExecutionException异常。
DiscardPolicy:丢弃任务,但是不抛出异常。
DiscardOldestPolicy:丢弃队列最近的任务,并执行当前任务。
CallerRunsPolicy:由提交任务的线程处理该任务。
Executors 静态工厂
Executors类里有四个线程池创建的静态工厂方法。它是Spring框架提供的线程池技术。底层是基于JDK的ThreadPoolExecutor实现。
分别为:FixedThread、CachedThread、ScheduledThread、SingleThread。
FixedThreadPool 固定大小
初始化指定线程数的线程池,核心线程与最大并发数相同,当线程池没有可执行任务时,也不会释放空闲线程,无界队列。
Executors.newFixedThreadPool(10);
//底层实现
new ThreadPoolExecutor(10, 10, 0L
,TimeUnit.MILLISECONDS
,new LinkedBlockingQueue<Runnable>());
CachedThreadPool 可缓存
初始化可缓存线程的线程池,默认空闲线程缓存60s,核心线程数是0,最大并发线程为Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue作为阻塞队列;
Executors.newCachedThreadPool();
//底层实现
new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L
, TimeUnit.SECONDS
,new SynchronousQueue<Runnable>());
线程池的最大值了Integer.MAX_VALUE会导致无限创建线程,注意控制并发的任务数,如果短时创建大量线程,会导致严重的性能问题。线程创建及任务对象会占用堆外内存,它就会使堆外内存和堆内内存其中的一个先耗尽,导致OOM。
ScheduledThreadPool 定时任务
初始化指定的时间周期性的执行任务,核心线程数是1,最大并发线程为Integer.MAX_VALUE,缓存为0。new DelayedWorkQueue()这个类是内部类,为了解它的实现本质在这里直接写。
Executors.newScheduledThreadPool(5);
//底层实现
new ThreadPoolExecutor(1, Integer.MAX_VALUE, 0,
NANOSECONDS,
new DelayedWorkQueue());
SingleThread 单线程
初始化只有一个线程的线程池。核心线程与并发数都是1个,缓存为0。无界阻塞队列。
Executors.newSingleThreadExecutor()
//底层实现
new FinalizableDelegatedExecutorService(
new ThreadPoolExecutor(1, 1,0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>())
);
特性:该线程异常结束,会重新创建一个新的线程继续执行任务。
任务Worker
线程池中的任务都被封装成了Worker对象。
Worker类 继承了AQS 类实现了加锁机制;
Worker类 实现了Runnable接口,表示是一个线程。
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
final Thread thread;
Runnable firstTask;
volatile long completedTasks
Worker(Runnable firstTask) {
setState(-1);//设置ASQ的state为-1,设置worker处于不可加锁的状态,为0时允许加锁
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
}
任务队列 Workes
添加任务时会存放到一个HashSet的workers队列中。保证worker对象的唯一性。
//HashSet 排列无序,且值不可重复。
private final HashSet<Worker> workers = new HashSet<Worker>();
线程池五个状态
running < shutdown < stop < tidying < terminated
当线程池中的执行数量 >= 核心线程数时,为RUNNING状态。表示此情况下才允许将新任务添加任务队列中。
其它状态都不会接收新任务,不会执行任务队列中的任务;
线程池运行机制 ![](https://img-blog.csdnimg.cn/direct/a21bf912712f4043b00f081baa8a9550.png)
提交任务 execute
- 当线程池执行数量< core ,新建一个线程执行任务;
- 当线程池执行数量 >= core && < maxPool,则创建一个新的线程,放入任务队列;
- 当线程池执行数量 > core && 存活时间超过keepalive时,则销毁线程;
- 当workers队列数量 >= maxPool && 没有空闲的线程,则拒绝新任务;
添加线程 addWorker
- 先判断线程池是否为RUNNING状态,再判断线程池有没有达到最大线程数限制;
- 创建work对象添加到works任务队列中等待并更新largestPoolSize池子数量;
- 最后启动线程:判断work对象中firstTask不为null,则执行第一个任务;依次循环。