线程池从名字行就可以理解为有很对个线程的一个池子,它负责对我们的线程进行管理,不需要我们在使用线程的时候频繁的创建和销毁。
线程池的优点
- 降低资源消耗:避免了线程频繁的创建和销毁带来的消耗
- 提高响应速度:当任务到达的时候,不用再创建线程,可以由线程池中空闲的线程来执行
- 提高线程的可管理性:如果线程无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以对线程进行统一的分配,监控和调优
线程池的创建
三大方法
//一个线程池只有一个线程
ExecutorService service = Executors.newSingleThreadExecutor();
//一个线程池可以有多个线程
ExecutorService service1 = Executors.newFixedThreadPool(10);
//线程池中的线程数是不固定的
ExecutorService service2 = Executors.newCachedThreadPool();
注意:线程池的创建不要使用Executors去创建,应该使用ThreadPoolExecutor去创建,使用Executors创建会有以下弊端:
FixedThreadPool
和SingleThreadPool
允许的请求队列长度为Integer.MAX_VALUE,可能会造成大量请求的堆积,从而导致OOM(OutOfMemory)CachedThreadPool
和ScheduledThreadPool
允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM
七大参数
public ThreadPoolExecutor(int corePoolSize, //核心线程数
int maximumPoolSize, //最大线程数
long keepAliveTime, //线程存活时间
TimeUnit unit, //线程存活时间单位
BlockingQueue<Runnable> workQueue, //工作队列
ThreadFactory threadFactory, //线程工厂
RejectedExecutionHandler handler) //拒绝策略
执行流程
- 当一个任务到达时,如果此时核心线程没有被全部使用,则会调用核心线程来处理任务
- 如果此时核心线程已满,并且工作队列没有满时,会将这个任务放入工作队列
- 如果工作队列已满,则会创建一个线程从工作队列中取出一个任务进行处理,然后将新的任务添加到工作队列中
- 如果此时线程池中的线程数已经到达maximumPoolSize,则会触发线程池的拒绝策略,也就是说线程池中的线程总数只要超过最大线程数,就会触发拒绝策略
- 对于线程池中空闲的线程,只要存活时间超过keepAliveTime个unit,就会进行回收
四种拒绝策略
线程池对于线程数达到最大线程数并且工作队列已经满时就会触发拒绝策略,不同的拒绝策略用不同的处理方式:
- AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
- DiscardPolicy:丢弃任务但不抛出异常,如果工作队列已满,则后续提交的任务都会丢弃
- CallerRunPolicy:不处理此任务,并将此任务交给线程的调用者执行
- DiscardOldestPolicy:将工作队列中最前面的也就是进入队列最早的任务抛弃,然后将新的任务添加到队尾