Java中线程池原理以及参数说明
本篇博文为转载,转载连接如下:
https://www.cnblogs.com/guofuangela/p/14381030.html
https://segmentfault.com/a/1190000019319050
线程池的类结构
1.Executor:线程池的核心接口,负责线程的创建使用和调度的根接口
public interface Executor {
// Executor 的定义非常简单,就定义了线程池最本质要做的事,执行任务。
void execute(Runnable command);
}
2.ExecutorService: Executor的子接口,线程池的主要接口, 提供基本功能。
ExecutorService 也是个接口,不过他算是把线程池的框架搭出来了,告诉要实现它的线程池必须提供的一些管理线程池的方法。
3.AbstractExecutorService 是普通的线程池执行器
4.ScheduledExecutorService 是定时任务线程池。
实现类
1.ThreadPoolExecutor:ExecutorService的实现类,负责线程池的创建使用。
2.ScheduledThreadPoolExecutor:继承 ThreadPoolExecutor,并实现 ScheduledExecutorService接口,既有线程池的功能,又具有线程调度功能。
3 Executors:线程池的工具类,负责线程池的创建。
static ExecutorService newFixedThreadPool(int nThreads)
//创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
static ExecutorService newCachedThreadPool()
//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
static ExecutorService newSingleThreadExecutor()
//创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
//创建一个定长线程池,支持定时及周期性任务执行。
线程池的基本原理
第一步便是我们将我们的任务提交给线程池
如果线程池中线程数小于核心线程数,则创建一个新的线程来执行该任务。否则进入步骤3
提交任务时,线程池中的空闲的线程数为0并且线程数等于核心线程数,则观察线程池中的任务队列是否已满,如果未满则将任务添加到任务队列,否则进入步骤4
如果最大线程数大于核心线程数,并且总线程数小于最大线程数,则创建一个新的线程来执行该任务。否则进入步骤5
当任务队列已满时,就执行拒绝策略(后续详解拒绝策略)
线程池核心类ThreadPoolExecutor参数和拒绝策略
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
//省略具体的代码内容
}
参数 说明
corePoolSize 核心线程数
maximumPoolSize 最大线程数,一般大于等于核心线程数
keepAliveTime 线程存活时间(针对最大线程数大于核心线程数时,非核心线程)
unit 存活时间单位,和线程存活时间配套使用
workQueue 任务队列
threadFactory 创建线程的工程
handler 拒绝策略
workQueue主要有三种类型:
ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue。
第一个是有界阻塞队列,第二个是无界阻塞队列,当然也可以为其指定界限大小,第三个是同步队列,对于ArrayBlockingQueue,其是需要指定队列大小的,当队列存满了任务线程池就会创建新的线程执行任务,对于LinkedBlockingQueue,如果其指定界限,那么和ArrayBlockingQueue区别不大,如果其不指定界限,那么其理论上是可以存储无限量的任务的,实际上能够存储Integer.MAX_VALUE个任务(还是相当于可以存储无限量的任务),此时由于LinkedBlockingQueue是永远无法存满任务的,因而maxPoolSize的设定将没有意义,一般其会设定为和corePoolSize相同的值。对于SynchronousQueue,其内部是没有任何结构存储任务的,当一个任务添加到该队列时,当前线程和后续添加任务的线程都会被阻塞,直至有一个线程从该队列中取出任务,当前线程才会被释放,因而如果线程池使用了该队列,那么一般corePoolSize都会设计得比较小,maxPoolSize会设计得比较大,因为该队列比较适合大量并且执行时间较短的任务的执行;
拒绝策略有以下几种
拒绝策略 说明
AbortPolicy 为java线程池默认的阻塞策略,不执行此任务,而且直接抛出一个运行时异常。
DiscardOldestPolicy 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
DiscardPolicy 也是丢弃任务,但是不抛出异常
CallerRunsPolicy 由调度线程处理该任务