01 缘由
线程池是多线程的一种处理方式. 可以统一管理线程, 某些情况下可复用线程, 减少内存开支, 提供更多功能(定时执行, 并发控制等).
02 了解
常见有四种线程池, 由 Executors 创建.
ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); //可缓存线程池 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10); //固定大小线程池 ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10); //周期任务线程池 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); //单线程化线程池
但是点开实现, 每个线程池的创建方法都是类似的.
//newCachedThreadPool()
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0,
Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
//newFixedThreadPool() public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } //newScheduledThreadPool() supe:ThreadPoolExecuotr public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); } //newSingleThreadExecutor() public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
追踪源头 ThreadPoolExecutor 的构造方法:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
序号 | 名称 | 类型 | 含义 |
---|---|---|---|
1 | corePoolSize | int | 核心线程池大小 |
2 | maximumPoolSize | int | 最大线程池大小 |
3 | keepAliveTime | long | 线程最大空闲时间 |
4 | unit | TimeUnit | 时间单位 |
5 | workQueue | BlockingQueue<Runnable> | 线程等待队列 |
6 | threadFactory | ThreadFactory | 线程创建工厂 |
7 | handler | RejectedExecutionHandler | 拒绝策略 |
1.当线程池小于corePoolSize时, 新提交任务将创建一个新线程执行任务, 即使此时线程池中存在空闲线程. 需要注意的是在初创建线程池时线程不会立即启动, 直到有任务提交才开始启动线程并逐渐时线程数目达到corePoolSize. 若想一开始就创建所有核心线程需调用prestartAllCoreThreads方法.
2.当线程池达到corePoolSize时, 新提交任务将被放入workQueue中, 等待线程池中任务调度执行.
3.当workQueue已满, 且maximumPoolSize>corePoolSize时, 新提交任务会创建新线程执行任务.
4.当提交任务数超过maximumPoolSize时, 新提交任务由RejectedExecutionHandler处理. 需要注意的是在初创建线程池时线程不会立即启动, 直到有任务提交才开始启动线程并逐渐时线程数目达到corePoolSize, 若想一开始就创建所有核心线程需调用prestartAllCoreThreads方法.
5.当线程池中超过corePoolSize线程, 空闲时间达到keepAliveTime时, 关闭空闲线程.
6.当设置allowCoreThreadTimeOut(true)时, 线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭.
7.当阻塞队列已满且线程数达到最大值时会采取对应的拒绝策略RejectedExecutionHandler, java默认提供了4种拒绝策略的实现方式: 中止, 抛弃, 抛弃最旧的, 调用者运行.
阻塞队列, 线程工厂, 拒绝策略有需求的可以自己指定.
Alibaba命名规范的解释:
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明: Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool : 允许的请求队列长度为 Integer.MAX_VALUE ,可能会堆积大量的请求,从而导致 OOM 。
2) CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OOM 。