android线程池的使用方法和原理

线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制的产生,并且线程的创建和销毁都会有相应的开销。当系统中存在大量的线程时,系统会通过时间片轮转的方式调度每个线程,因此线程不可能做到绝对的并行,除非CPU核心数>线程数,一般来说是不可能的。试想一下如果在一个进程中频繁的创建和销毁线程,显然不是高效的做法。正确的方法是使用线程池,一个线程池会缓存一定数量的线程,做到线程重用、有效控制最大并发数,避免因为频繁创建和销毁线程带来的系统开销。


如何创建并配置线程池:

线程池的概念来源于Java的Executor,Executor是一个接口,真正的线程池的实现为ThreadPoolExecutor它的构造方法提供了一系列参数来配置线程池

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

corePoolSize:指线程池的核心线程数,默认情况下核心线程会在线程池中一直存活,即时它们处于闲置状态。但如果将ThreadPoolExecutor的allowCoreThreadTimeOut属性置为true,那么如果核心线程等待的时长超过keepAliveTime,核心线程就会被终止。

maximumPoolSize:线程池所能容纳的最大线程数,当活动线程达到这个数值后,后续的新任务将会被阻塞。

keepAliveTime:非核心线程闲置时的超时时长,超过时长就会被回收。allowCoreThreadTimeOut属性置为true,那么这个属性对核心线程亦有效。

unit:keepAliveTime的时间单位,如TimeUnit.MILLISECONDS(毫秒)。

workQueue:线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这里。

threadFactory:线程工厂,为线程池创建新线程。ThreadFactory只有一个方法:Thread newThread(Runnable r)。

RejectedExecutionHandler:当线程池无法执行新任务时,可能是由于任务队列已满或无法成功执行任务,这时ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution方法,默认rejectedExecution会直接抛出一个RejectedExecutionException(走AbortPolicy的实现)。


ThreadPoolExecutor执行任务的规则:

  1. 如果线程池中的线程数量未达到核心线程的数量,那么会直接创建一个核心线程执行任务。(注意核心线程、非核心线程都是线程池创建的,并非外界赋予线程池的,外界只是赋予任务)

  2. 如果任务无法插入到任务队列中,往往是因为任务队列已满。这时如果线程数量未达线程池规定的最大值,那么会立刻创建一个非核心线程来执行任务。(注意任务队列的长度跟线程池所能容纳的最大线程数不是一个概念)

  3. 如果2中线程数量已达线程池规定的最大值,那么线程池会拒绝执行任务,ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution方法来通知调用者。


AsyncTask内部就是使用了线程池,来看一下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);

public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

可见AsyncTask配置的线程池规格如下:
核心线程数:CPU核心数 + 1
最大线程数:2 * CPU核心数 + 1
非核心线程闲置时间:1秒
任务队列长度:128


线程池的分类

Android中常见的有4类线程池,它们也是通过配置ThreadPoolExecutor来实现自己的功能特性:

1. FixedThreadPool

特点:线程数量固定,只有核心线程,当线程处于空闲状态时不会被回收,任务队列大小无限制。

创建方法:

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

2. CachedThreadPool

特点:只有非核心线程,最大线程数可以任意大,所以任何任务都会被立刻执行,空闲线程超时时长为60秒,适合执行大量的耗时较少的任务。

创建方法:

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

3. ScheduledThreadPool

特点:核心线程数量固定,非核心线程数量无限制,非核心线程空闲时会被立刻回收,适合执行定时任务和具有固定周期的重复任务。

创建方法:

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

4. SingleThreadExecutor

特点:内部只有一个核心线程,能确保所有任务在同一个线程中顺序执行,任务之间不需处理线程同步的问题。

创建方法:

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

使用示例:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        SystemClock.sleep(2000);    
    }
};

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
//1秒后执行runnable
scheduledThreadPool.schedule(runnable, 1000, TimeUnit.MILLISECONDS);
//0.5秒后每1秒执行一次runnable
scheduledThreadPool.scheduleAtFixedRate(runnable, 500, 1000, TimeUnit.MILLISECONDS);

ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
singleThreadPool.execute(runnable);
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值