Android ThreadPoolExecutor线程池

引言

Android的线程池概念来自于Java的Executor,真正的线程池实现为ThreadPoolExecutor。在Android中,提供了4类不同的线程池,具体下面会说到。为什么使用线程池呢?而不是使用Thread创建线程呢?因为使用线程池有以下几个优点:

  • 重用线程池的线程,避免因为线程的创建和销毁所带来的性能开销
  • 能有效控制线程池的最大并发数,避免线程之间抢占资源导致阻塞
  • 能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能

所以需要多次创建Thread时使用线程池较好。

ThreadPoolExecutor

它是线程池的真正实现,构造函数提供一系列的参数配置线程池。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
  • corePoolSize:核心线程数,默认情况下,即时处于闲置状态下,核心线程会在线程一直存活;如果设置allowCoreThreadTimeOut为true,闲置的核心线程等待任务期间会有超时策略,时间间隔由keepAliveTime设置,最大为CPU核心数+1
  • maximumPoolSize:线程池容纳最大线程数,当活动线程数超过这个数值,后续的新任务会导致阻塞,最大为CPU核心数2倍+1
  • keepAliveTime:非核心线程闲置时超时的时长,如果设置allowCoreThreadTimeOut为true,即作用于闲置的核心线程
  • unit:时间单位,使用TimeUnit枚举
  • workQueue:线程池中的任务队列,通过线程池execute方法提交Runnable对象会存储这个参数中,容量为128
  • threadFactory:线程工厂,为线程池提供创建新线程的功能
  • handler:线程池对拒绝任务的处理策略。一般是队列已满或者无法成功执行任务,这时ThreadPoolExecutor会调用handler的rejectedExecution方法来通知调用者,有四个策略:
    • ThreadPoolExecutor.AbortPolicy() 直接抛出异常RejectedExecutionException
    • ThreadPoolExecutor.CallerRunsPolicy() 直接调用run方法并且阻塞执行
    • ThreadPoolExecutor.DiscardPolicy() 直接丢弃后来的任务
    • ThreadPoolExecutor.DiscardOldestPolicy() 丢弃在队列中队首的任务

执行任务规则可用currentSize表示线程池中当前线程数量,将上述过程可以表示如下

  • 当currentSize < corePoolSize时,直接启动一个核心线程并执行任务
  • 当currentSize>=corePoolSize、并且workQueue未满时,添加进来的任务会被安排到workQueue中等待执行
  • 当workQueue已满,但是currentSize<maximumPoolSize时,会立即开启一个非核心线程来执行任务
  • 当currentSize>=corePoolSize、workQueue已满、并且currentSize>maximumPoolSize时,调用handler默认抛出RejectExecutionExpection异常
  • 当currentSize >corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
  • 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

FixedThreadPool

通过Executors的newFixedThreadPool方法创建,它是一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。由于FixedThreadPool只有核心线程并且这些核心线程不会被回收,这意味着它能够更加快速地响应外界的请求。

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

CachedThreadPool

通过Executors的newCachedThreadPool方法创建,它是一种线程数量不定的线程池,它只有非核心线程,并且最大线程数为Integer.MAX_VALUE,从CachedThreadPool的特性来看,这类线程池比较适合执行大量的耗时较少的任务,当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候CachedThreadPool之中实际上是没有任何线程的,它几乎是不占用任何系统资源的。

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

ScheduledThreadPool

通过Executors的newScheduledThreadPool方法创建,它的核心线程是固定的,非核心线程数是没有限制的,主要用于执行定时任务和具有固定周期的重复任务。

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

SingleThreadExecutor

通过Executors的newSingleThreadExecutor方法创建,它只有一个核心线程,确保所有任务都在同一个线程中按顺序执行,使得这些不需要处理线程同步问题。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
posted @ 2018-11-20 17:18  fomin  阅读(863)  评论(0编辑  收藏  举报