Android 线程池详解

前言

做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. 感觉作用就是不用担心线程同步了,,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值