系列文章目录
第一章 Android线程池深入浅出(一)
第二章 Android线程池深入浅出(二)
线程池进阶
前言
在《Android线程池深入浅出(一)》中我们已基本了解了线程的优缺点、如何创建,根据不同的初始化参数配置更适合项目使用的线程池实例,本章内容将详细讲解线程池的相关进阶内容,请往下细读。
一、线程的创建策略
线程池中线程的创建时机和corePoolSize以及workQueue 两个参数有关,它有自己的一定的逻辑规律。
线程情况 | 策略 |
---|---|
线程数量小于 corePoolSize | 直接创建新线程处理新的任务 |
线程数量大于等于 corePoolSize,workQueue 未满 | 则缓存新任务 |
线程数量大于等于 corePoolSize,但小于 maximumPoolSize,且 workQueue 已满 | 则创建新线程处理新任务 |
线程数量大于等于 maximumPoolSize,且 workQueue 已满 | 则使用拒绝策略处理新任务 |
线程创建的逻辑图如下:
二、 线程资源回收策略
考虑到系统资源是有限的,对于线程池超出 corePoolSize 数量的空闲线程应进行回收操作。进行此操作存在一个问题,即回收时机。目前的实现方式是当线程空闲时间超过 keepAliveTime 后,进行回收。
除了核心线程数之外的线程可以进行回收,核心线程内的空闲线程也可以进行回收。回收的前提是allowCoreThreadTimeOut属性被设置为 true。
public void allowCoreThreadTimeOut(boolean value) {
...
}
三、排队策略
如上面线程创建规则所说的,当线程数量大于等于corePoolSize,workQueue未满时,则缓存新任务。这里要考虑使用什么类型的容器缓存新任务,通过 JDK 文档介绍,我们可知道有3种类型的容器可供使用,分别是同步队列,有界队列和无界队列。对于有优先级的任务,这里还可以增加优先级队列。
以上所介绍的4种类型的队列,对应的实现类如下:
实现类 | 类型 | 说明 |
---|---|---|
SynchronousQueue | 同步队列 | 该队列不存储元素,每个插入操作必须等待另一个线程调用移除操作,否则插入操作会一直阻塞 |
ArrayBlockingQueue | 有界队列 | 基于数组的阻塞队列,按照 FIFO 原则对元素进行排序 |
LinkedBlockingQueue | 无界队列 | 基于链表的阻塞队列,按照 FIFO 原则对元素进行排序 |
PriorityBlockingQueue | 优先级队列 | 具有优先级的阻塞队列 |
四、拒绝策略
如上线程创建规则策略中所说,当线程数量大于等于 maximumPoolSize,且 workQueue 已满,或者是当前线程池被关闭了则使用拒绝策略处理新任务。
Java 线程池提供了4种拒绝策略实现类, 如下:
实现类 | 说明 |
---|---|
AbortPolicy | 丢弃新任务,并抛出 RejectedExecutionException |
DiscardPolicy | 不做任何操作,直接丢弃新任务 |
DiscardOldestPolicy | 丢弃队列列首的元素,并执行新任务 |
CallerRunsPolicy | 会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。 |
以上4个拒绝策略中,AbortPolicy 是线程池实现类所使用的默认策略。我们也可以通过ThreadPoolExecutor的如下方法来修改线程池的拒绝策略。
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
...
}
五、线程是如何创建的
在线程池的实现上,线程的创建是通过线程工厂接口ThreadFactory的实现类来完成的。默认情况下会返回一个ThreadFactory的实现类DefaultThreadFactory对象。
public static ThreadFactory defaultThreadFactory() {
return new DefaultThreadFactory();
}
/**
* The default thread factory
*/
private static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
/**
* 创建线程设置优先级和线程名
*/
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
当然,我们也可以通过方法setThreadFactory(ThreadFactory threadFactory),我们也可以设定为自定义的线程工厂。
总结
。。。