Android线程池深入浅出(二)

系列文章目录

第一章 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),我们也可以设定为自定义的线程工厂。

总结

。。。

猜你喜欢

转载自blog.csdn.net/luo_boke/article/details/108754669