为什么使用线程池

线程池提供了一种限制和管理资源(包括执行一个任务)。

优势:

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行
  • 提高线程的可管理性。线程时稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控

线程池执行任务的流程

线程池_等待队列

1.线程池执行execute/submit方法向线程池添加任务,当任务小于核心线程数corePoolSize,线程池中可以创建新的线程。

2.当任务大于核心线程数corePoolSize,就向阻塞队列添加任务。

3.如果阻塞队列已满,需要通过比较参数maximumPoolSize,在线程池创建新的线程,当线程数量大于maximumPoolSize,说明当前设置线程池中线程已经处理不了了,就会执行饱和策略。


线程池的状态转换

线程池_阻塞队列_02

  • RUNNING:能接收新提交的任务,也能处理阻塞队列中的任务
  • SHUTDOWN:关闭状态,不再接收新提交的任务,但却可以继续处理阻塞队列中已保存的消息
  • STOP:不接受任务,也不处理阻塞队列中的消息,会中断正在执行的任务
  • TIDYING:所有的任务已终止,workerCount(有效线程数为0)
  • TERMINATED:在 terminated()方法执行完后进入该状态

创建线程

Executors工厂方法创建

newSingleThreadExecutor()

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}

该线程池存在的问题:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

newFixedThreadPool(n)

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}

该线程池存在的问题:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

newCachedThreadPool()

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

该线程池存在的问题:允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程,从而导致 OOM。

newScheduledThreadPool(n)

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}

该线程池存在的问题:允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程,从而导致 OOM。


ThreadPoolExecutor 创建

参数说明:

  • corePoolSize:核心线程数,默认情况下,核心线程会一直存活,即使处于闲置状态也不会受存活时间keepAliveTime的限制,除非将allowCoreThreadTimeOut设置为True
  • maximumPoolSize:线程池所能容纳的最大线程数。超过这个数的线程将被阻塞,当任务队列为没有设置大小的LinkedBlockingDeque时,这个值无效
  • keepAliveTime:非核心线程的限制超时时间,超过这个时间就会被回收
  • unit:指定keepAliveTime的单位,如TimeUnit.SECONDS。当将allowCoreThreadTimeOut设置为true时,对corePoolSize生效
  • workQueue:线程池中的任务队列,常用的有三种队列:
  • SynchronousQueue:是一种无缓冲的等待队列,再某次添加元素后必须等待其他线程取走后才能继续添加
  • LinkedBlockingQueue:是一种无界缓存的等待队列,不指定容量则为Integer的最大值,锁是分离的
  • ArrayBlockingQueue:是一种有界缓存的等待队列,必须指定大小,锁是没有分离的
  • threadFactory:线程工厂,提供创建新线程的功能,通过线程工厂可以对线程的一些属性进行定制
  • RejectedExecutionHandler:当线程池中的资源已经全部使用,添加新线程被拒绝时,会调用RejectedExecutionHandler的rejectedExecution方法,线程池有一下四种拒绝策略
  • AbortPolicy:当任务添加到线程池中被拒绝时,他将抛出RejectedExecutionException异常(默认的拒绝策略)
  • CallerRunsPolicy:当任务被添加到线程池中被拒绝时,会再线程池当前正在运行的Thread线程池中处理被拒绝的任务
  • DiscardOldestPolicy:当任务被添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务天机道等待队列中
  • DiscardPolicy:当任务被添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务

四种构造方法:方式一

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,
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) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

提交任务方式

提交方式

是否关心返回结果

​Future<T> submit(Callable<T> task)​

​void execute(Runnable command)​

​Future<?> submit(Runnable task)​

否,虽然返回Future,但是其get()方法总是返回null

四种拒绝策略

线程池_线程池_03

拒绝策略

拒绝行为

AbortPolicy

抛出RejectedExecutionException

DiscardPolicy

什么也不做,直接忽略

DiscardOldestPolicy

丢弃执行队列中最老的任务,尝试为当前提交的任务腾出位置

CallerRunsPolicy

直接由提交任务者执行这个任务

线程池默认的拒绝行为是​​AbortPolicy​​​,也就是抛出​​RejectedExecutionHandler​​​异常,该异常是非受检异常,很容易忘记捕获。如果不关心任务被拒绝的事件,可以将拒绝策略设置成​​DiscardPolicy​​,这样多余的任务会悄悄的被忽略。