Android 线程池的类型、区别以及为什么要用线程池

每一个 Android 应用进程在建立时,会同时建立一个线程,咱们称之为主线程,负责更新 UI 界面以及和处理用户之间的交互,所以,在 Android 中,咱们又称之为 UI 线程。一个进程中 UI 线程只有一个,为了避免形成界面卡顿、提升用户体验,咱们势必要将一些耗时操做交由子线程来执行。html

使用子线程的方式主要分两种:java

  • 直接使用 ThreadRunnable 等建立子并使用线程linux

  • 使用线程池建立并使用子线程android

线程池是什么多线程

线程池是指在初始化一个多线程应用程序过程当中建立一个线程集合,而后在须要执行新的任务时重用这些线程而不是新建立一个线程。线程池中线程的数量一般彻底取决于可用内存数量和应用程序的需求;每一个线程都有被分配一个任务,一旦任务完成了,线程回到池子中并等待下一次分配任务。异步

通常状况下,推荐使用线程池来建立和使用子线程,不建议使用第一种方式。函数

为什么要用线程池

上面说了,在 Android 开发过程当中,建议使用线程池来建立和使用子线程,那么使用线程池的好处有哪些呢?性能

  • 线程池改进了一个应用程序的响应时间。因为线程池中的线程已经准备好且等待被分配任务,应用程序能够直接拿来使用而不用新建一个线程。优化

  • 线程池节省了 CLR 为每一个短生存周期任务建立一个完整的线程开销并能够在任务完成后回收资源。google

  • 线程池根据当前在系统中运行的进程来优化线程片。

  • 线程池容许咱们开启多个任务而不用为每一个线程设置属性。

  • 线程池容许咱们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。

  • 线程池能够用来解决处理一个特定请求最大线程数量限制问题。

  • 系统分配给每一个应用的线程栈是固定的,使用线程池能够有效地避免线程栈溢出引发的应用崩溃。

Android 中的线程池

Android 中线程池的真正实现是 ThreadPoolExecutor,其构造方法有 5 个,经过一系列参数来配置线程池。下面介绍一个比较经常使用的构造方法及其参数的含义。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory)
参数 含义
corePoolSize int: 线程池的核心线程数,默认状况下,核心线程回一直在线程池中存活,即便他们处于闲置状态。若是将 allowCoreThreadTimeOut 的属性设置为 true,那么闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由 keepAliveTime 所指定,当等待时间超过 keepAliveTime 所指定的时长后,核心线程就会被终止。
maximumPoolSize int: 线程池中容许的线程最大数量,当活动线程达到这个数值后,后续的新任务会被阻塞。
keepAliveTime long: 非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收。当 allowCoreThreadTimeOut 属性被设置为 true 时,该参数一样会做用于核心线程。
unit TimeUnit: keepAliveTime 参数的时间单位 ,参数为 TimeUnit 的枚举,常见的有 TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECOND(秒) 等。
workQueue BlockingQueue: 线程池中的任务队列,经过线程池的 execute 方法提交的 Runnable 对象会存储在这个参数中。
threadFactory ThreadFactory: 建立线程的线程工厂。ThreadFactory 是一个接口,只有一个方法:Thread newThread (Runnable r)
Throws  
IllegalArgumentException 符合如下任一条件,则抛出此异常: corePoolSize < 0 keepAliveTime < 0 maximumPoolSize <= 0 maximumPoolSize < corePoolSize
NullPointerException workQueue 或者 threadFactory 为 null 时,抛出此异常。

ThreadPoolExecutor 执行任务时大体遵循以下规则:

  1. 若是线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。

  2. 若是线程池中的线程数量已经达到或超过核心线程的数量,那么任务会被插入到任务队列中等待执行。

  3. 若是步骤 2 中没法将任务插入到任务队列,则表示任务队列已满。此时,若是线程数量未达到 maximumPoolSize 值,则会当即启动一个非核心线程来执行任务。

  4. 若是步骤 3 中线程数量大于或等于 maximumPoolSize 值,则拒绝执行次任务,此时 ThreadPoolExecutor 会调用 RejectedExecutionHandlerrejectedExecution 来通知调用者。

RejectedExecutionHandler 是线程池持有的一个对象,用于不能由 ThreadPoolExecutor 执行的任务的处理

Android 中线程池的类型及区别

Android 中最多见线程池有四种,分别是:FixedThreadPool、CacheThreadPool、ScheduledThreadPool 以及 SingleThreadPool,它们都直接或间接的经过配置 ThreadPoolExecutor 来实现本身的功能特性。

1. FixedThreadPool

线程数量固定的线程池,经过 ExecutorsnewFixedThreadPool 方法建立。有两个重载的建立方法:

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

除非线程池被关闭,不然线程不会被回收,即时线程处于空闲状态。若是在全部线程都处于活动状态时提交额外的任务,它们将在队列中等待,直到有一个线程可用为止。由建立方法可知,FixedThreadPool 只有核心线程而且这个核心线程没有超时机制(keepAliveTime 参数为 0L),加上线程不会被回收,所以使用此类线程池能够快速地响应外界的请求。

2. CacheThreadPool

线程数量不定的线程池,经过 ExecutorsnewCachedThreadPool 方法建立。有两个重载的建立方法:

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

CacheThreadPool 有如下个特征:

  • 没有核心线程( corePoolSize 参数为 0 ),只有非核心线程且非核心线程的数量为 Integer.MAX_VALUE,这就至关于非核心线程的数量能够无限大。

  • 线程池的线程处于空闲状态时,线程池会重用空闲的线程来处理新任务,不然建立新的线程来处理,新建立的线程会添加到线程池中。这将提升执行许多短时间异步任务的程序性能。

  • 闲置时间超过 60 秒的空闲线程会被回收(keepAliveTime 参数为 60L )。所以,闲置时间足够长的 CacheThreadPool 也不会消耗任何系统资源。

3. ScheduledThreadPool

核心线程数量固定,非核心线程数量不定的线程池,经过 Executorsnewscheduledthreadpool 方法建立。有两个重载的建立方法:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
        int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

ScheduledThreadPool 相比较其余三种线程池,有特殊性,由 ScheduledThreadPoolExecutor 实现, newscheduledthreadpool 方法也是经过建立 ScheduledThreadPoolExecutor 的实例来完成线程池的建立,代码以下:

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

ScheduledThreadPoolExecutor 的构造函数可知, ScheduledThreadPool 的核心线程数量是固定的,由传入的 corePoolSize 参数决定,非核心线程数量能够无限大。非核心线程闲置回收的超时时间为 10秒DEFAULT_KEEPALIVE_MILLIS 的值为 10L )。这类线程主要用于执行定时任务或者具备周期性的重复任务。

4. SingleThreadPool

只有一个核心线程,经过 Executorsnewsinglethreadexecutor 方法建立。有两个重载的建立方法:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(/* corePoolSize*/ 1, /* maximumPoolSize*/ 1,
                                /* keepAliveTime*/ 0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(/* corePoolSize*/ 1, /* maximumPoolSize*/ 1,
                                /* keepAliveTime*/ 0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}

SingleThreadPool 由 代理类 FinalizableDelegatedExecutorService 建立。该线程池只有一个线程(核心线程),而且该线程池的任务队列是无上限的,这就确保了全部的任务都在同一个线程中顺序执行。

注意,若是因为在执行期间出现故障而致使该线程终止,那么若是须要执行后续任务,则新线程将取而代之。

四类线程池的区别

上面分别对 Android 中常见的 4 种线程池进行了简单的介绍,除了这 4 种系统提供的线程池外,咱们在使用的过程当中,也能够根据须要直接经过 ThreadPoolExecutor 的构造函数来灵活的配置线程池。那么,上述的 4 种线程池,其区别在哪呢?了解其区别有助于咱们去选择更为合适的线程池或者直接经过 ThreadPoolExecutor 来配置更灵活的线程池。

FixedThreadPool 线程固定,且不会被回收,可以更快的响应外界请求

CachedThreadPool 只有非核心线程,且线程数至关于无限大,任何任务都会被当即执行。比较适合执行大量的耗时较少的任务。

ScheduledThreadPool 主要用于执行定时任务或者具备周期性的重复任务

SingleThreadPool 只有一个核心线程,确保全部任务都在同一线程中按顺序完成。所以不须要处理线程同步的问题

 

参考

相关文章
相关标签/搜索