目录
一. 前言
线程池可以看做是线程的集合。它的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后 启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕, 再从队列中取出任务来执行。他的主要特点为:线程复用;控制最大并发数;管理线程。
类结构关系:
二. 快速创建线程池
Executors类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。
1. 创建单线程的线程池
public static ExecutorService newSingleThreadExecutor()
源码实现:
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
2. 创建固定数目线程的线程池
public static ExecutorService newFixedThreadPool(int nThreads)
源码实现:
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
3. 创建可缓存的线程池
public static ExecutorService newCachedThreadPool()
将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
源码实现:
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
4. 创建支持定时及周期性的任务执行的线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
多数情况下可用来替代Timer类
源码实现:
new ScheduledThreadPoolExecutor(corePoolSize);
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor
implements ScheduledExecutorService {
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
}
Executors只是对线程池一些特定情况的简洁使用,在生产场景被很多企业的开发规范所禁用。因为会有内存溢出的风险,直接用ThreadPoolExecutor构造线程池会获得更为强大的功能。
newSingleThreadExecutor,newFixedThreadPool阻塞队列LinkedBlockQueue的初始容量为int.MAX_VALUE
newCachedThreadPool,newScheduledThreadPool 最大线程数为int.MAX_VALUE
三. 线程池核心参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
1. corePoolSize 线程池核心线程数
线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。任务提交到线程池后,首先会检查当前线程数是否达到了corePoolSize,如果没有达到的话,则会创建一个新线程来处理这个任务。
2. maximumPoolSize 线程池最大线程数
当前线程数达到corePoolSize后,如果继续有任务被提交到线程池,会将任务缓存到工作队列(后面会介绍)中。如果队列也已满,则会去创建一个新线程来处理。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。
3. keepAliveTime 空闲线程存活时间
一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定
4. unit 空闲线程存活时间单位
keepAliveTime的计量单位,可以是秒,豪秒,纳秒
5. workQueue 工作队列
核心线程数满后,新的任务会进入到此工作队列中,任务调度时再从队列中取出任务。
JDK提供了4种工作队列:ArrayBlockingQueue、LinkedBlockingQuene、SynchronousQuene、PriorityBlockingQueue
6. threadFactory 线程工厂
创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等。
7. handler 拒绝策略
当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略:
7.1. DiscardPolicy
默认策略,直接丢弃任务,且不抛出异常。
7.2. AbortPolicy
直接丢弃任务,并抛出RejectedExecutionException异常。
7.3. CallerRunsPolicy
在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。
7.4. DiscardOldestPolicy
抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列。
7.5. 自定义策略
实现接口RejectedExecutionHandler,自定义拒绝策略。