Android中的线程池ThreadPoolExecutor

来源:互联网 发布:杭州java应届生招聘 编辑:程序博客网 时间:2024/06/05 19:31

线程池主要相关的有如下几个类:
1、Executor
最底层的接口,规定了一个void execute(Runnable command)接口,用于执行线程任务;

2、ExecutorService、AbstractExecutorService
ExecutorService抽象类继承Executor接口,AbstractExecutorService抽象类继承ExecutorService。这两个抽象类对线程池做了进一步封装;

3、ThreadPoolExecutor
ThreadPoolExecutor是就是线程池最终的实现了,继承自AbstractExecutorService抽象类;

4、Executors
Executors是一个快速创建ThreadPoolExecutor的工具类。提供了多个静态方法用于创建各种类型的线程池,其本质也是调用new ThreadPoolExecutor()方法创建的;

线程池的主要优点有三个:
1、重用线程,提高性能。创建、销毁线程都是很耗资源的;
2、控制线程数量,避免大量线程抢占资源而导致的阻塞现象;
3、能够对线程进行简单的管理。比如定时执行、排队执行等;

ThreadPoolExecutor

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、参数 int corePoolSize
线程池的核心线程数量。核心线程会一直存活,即使它们处于空闲状态。当然,如果将allowCoreThreadTimeOut属性设置为true,当核心线程空闲时间超过一定时间(由keepAliveTime属性指定)后,还是会终止;

2、参数 int maximumPoolSize
线程池所能容纳的最大线程数。当活动线程数达到极限后,新加入的线程会被阻塞;

3、参数 long keepAliveTime
线程空闲超时时间。当线程空闲时间超过这个值后,就会被系统终止;

4、参数 TimeUnit unit
用于指定keepAliveTime的时间单位。这是一个枚举值,常用的有毫秒MILLISECONDS、秒SECONDS、分钟MINUTES;

5、参数 BlockingQueue workQueue
存储任务的队列,就是存储了Runnable对象的集合。既然可以添加/存储很多Runnable对象,为什么还说线程数量是指定的呢?因为这个集合只是存储了Runnable对象,并不会调用其start()方法启动线程来执行任务,而是在指定的线程中调用Runnable对象的run()方法,执行run()方法里面的逻辑而已。

6、参数 ThreadFactory threadFactory
线程工厂,为线程池提供创建线程的功能。ThreadFactory是一个接口,它只声明了一个方法Thread newThread(Runnable r);

另外,ThreadPoolExecutor中还有个RejectedExecutionHandler handler成员变量,通过setRejectedExecutionHandler()方法设置。当线程池无法执行新任务时(比如线程已满),会通过这个handler通知调用处。

线程池执行任务时,会遵循如下规则:
1、如果线程数未达到corePoolSize,当有新任务插入的时候,会启动一个核心线程进行执行;
2、如果线程数已经达到corePoolSize,当有新任务插入时,会插入任务队列中排队等待;
3、如果任务队列也满了,就启动一个非核心线程执行该任务;
4、如果线程数已经达到maximumPoolSize,就拒绝该任务,并通过RejectedExecutionHandler通知调用处;

Executors

一般情况下,我们很少会自己new ThreadPoolExecutor,而是使用Executors工具类来快速创建所需的线程池,我们看一下Executors的几个常用方法:

1、固定线程数线程池

public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>());    }

可以看出,这个线程池核心线程数和最大线程数一样,所以这个线程池只有核心线程数,并且没有超时时间,即使线程空闲,也不会终止。由于这些线程都不会被回收,所以这样的线程池能快速响应外界请求。

2、单线程线程池

public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue<Runnable>()));    }

从构造方法的参数可以看出,这是一个单线程的线程池,里面只有一个核心线程。它的意义在于,统一在一个线程中处理所有任务,不需要考虑线程间的同步问题。

3、缓存线程池

public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());    }

这个线程池没有核心线程,全部是非核心线程,最大线程数是0x7fffffff,几乎等于无限,并且设置了60秒的超时时间。这个线程池的任务队列为SynchronousQueue,这个比较特殊,可以理解为它是一个无法存储元素的队列,也就是说这个线程池没有任务队列,即所有的新任务都会立即执行,要么启动新线程,要么使用空闲线程。这种线程池比较适合量大、耗时少的任务,当所有任务执行完,超过60秒就回收,几乎不占用系统资源。

4、定时线程池

public ScheduledThreadPoolExecutor(int corePoolSize,                                       ThreadFactory threadFactory) {        super(corePoolSize, Integer.MAX_VALUE,              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,              new DelayedWorkQueue(), threadFactory);    }

这个线程池的核心线程固定,非核心线程无限大,超时时间DEFAULT_KEEPALIVE_MILLIS为10毫秒,也就是空闲非核心线程立即回收。任务队列是延时任务队列,这类线程池主要是用来执行延时任务和重复任务的。

总结

一般情况下我们很少会自己来new这些线程池,但是SDK中很多地方都用到了线程池,上一篇研究了Handler,今天研究了线程池,学会了这两个工具,我们就可以定制出更高效、更简洁的异步任务处理方法了。

下一篇就以AsynTask源码为例子,来研究一下Handler和线程池在其中的运用。

1 0
原创粉丝点击