Android 线程池详解

来源:互联网 发布:python 改变路径 编辑:程序博客网 时间:2024/06/17 08:44

前言

做Android开发,有时会启动大量的线程,如果不适当的管理,会增加系统的开销,降低程序的性能。而线程池是Android性能优化的一个方案,有诸多好处:

 1. 可以重用线程池里的线程,避免线程的创建和销带来的性能开销。 2. 可以控制线程池的最大并发数,避免大量线程之前抢占系统资源而造成阻塞现象。 3. 可以对线程进行管理,比如定时执行某线程或是循环执行等功能。

ThreadPoolExecutor

我们知道Java中有一个Executor这样一个接口。而ExecutorService就是继承了Executor的一个接口,真正实现的是ThreadPoolExecutor。先看下ThreadPoolExecutor的构造方法(比较常用的):

public ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue<Runnable> workQueue,                              ThreadFactory threadFactory) {        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,             threadFactory, defaultHandler);    }

参数:

  • corePoolSize:核心线程。
  • maximumPoolSize:线程池所能容纳的最大线程数。
  • keepAliveTime:非核心线程闲置的超时时长,如果超过这个值,非核心线程就会被回收。
  • unit:用于指定keepAliveTime的时间单位。
  • workQueue:线程池中的任务队列。
  • threadFactory:为线程池提供新建线程的功能。

    这些参数配置在AsyncTask中就有所体现:

private static final String LOG_TAG = "AsyncTask";    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;    private static final int KEEP_ALIVE = 1;    private static final ThreadFactory sThreadFactory = new ThreadFactory() {        private final AtomicInteger mCount = new AtomicInteger(1);        public Thread newThread(Runnable r) {            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());        }    };    private static final BlockingQueue<Runnable> sPoolWorkQueue =            new LinkedBlockingQueue<Runnable>(128);    /**     * An {@link Executor} that can be used to execute tasks in parallel.     */    public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

从AsyncTask的代码,我们可以看出:

  1. 核心线程=cpu核心数+1
  2. 核心线程没有超时机制,非核心线程的闲置超时时间为1秒
  3. 线程池的最大线程数为cpu核心数*2+1
  4. 任务队列的容量为128

    ThreadPoolExecutor执行任务的时候,遵循以下规则:

    1 如果线程池里的线程数量没有达到核心线程的数量,那么会直接启动一个核心线程来执行任务。
    2 如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会被插入到任务队列中的排队等待执行。
    3 如果在步骤2中无法将任务插入到任务队列中,这往往是由于任务队列已满,这个时候如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来来执行。
    4 如果步骤3中线程数量已经达到线程规定的最大值,那么就拒绝执行此任务,ThreadPoolExecutor 就会调用RejecteExecutionHandler的rejectedExcution方法来通知调用者。


Android中的线程池

Android中也通过配置ThreadPoolExecutor来实现了不同类型的线程池,下面我们来介绍最常用的4类线程池:

1.FixedThreadPool

通过调用Executes的newFixedThreadPool方法来创建:

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

我们发现,FixedThreadPool线程池具备以下特性:

  1. 线程数量固定,在创建的时候,指定数量。
  2. 当线程处于空闲状态时,它们不会被回收,直到线程池被关闭。
  3. 当所有的线程都处于活动状态,新任务会处于等待状态,直到有线程空闲出来。
  4. 所有线程都是核心线程,且没有超时机制,队列也没有大小限制

2.CachedThreadPool

通过调用Executes的newCachedThreadPool方法来创建:

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

我们发现,CachedThreadPool线程池具备以下特性:

  1. 线程数量不固定,并且最大数为Integer.MAX_VALUE
  2. 当线程处于空闲状态时,如果闲置60秒就会被回收
  3. 当所有的线程都处于活动状态,新任务会创建新的线程执行,否则就使用闲置线程。
  4. 由此看来,CachedThreadPool线程池适合做大量的耗时较少的任务。

3.ScheduledThreadPool

通过调用Executes的newScheduledThreadPool方法来创建:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {        return new ScheduledThreadPoolExecutor(corePoolSize);    }
public ScheduledThreadPoolExecutor(int corePoolSize) {        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,              new DelayedWorkQueue());    }

我们发现,ScheduledThreadPool线程池具备以下特性:

  1. 核心线程是固定的,创建时指定
  2. 非核心线程是不固定的,闲置会被回收
  3. CachedThreadPool,主要用于执行定时任务和具有固定周期的重复任务

3.SingleThreadExecutor

通过调用Executes的newSingleThreadExecutor方法来创建:

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

我们发现,SingleThreadExecutor线程池具备以下特性:

  1. 内部只有一个核心线程
  2. 所有任务在线程中排队执行
  3. 感觉作用就是不用担心线程同步了,,
2 0