Android开发之线程与线程池

Android线程

Android的线程形式主要有四种

  1. Thread+Handler
  2. AsyncTask
  3. HandlerThread
  4. IntentService
对于第一种和第二种,已分别在Android的消息机制Android线程之AsyncTask使用与原理分析 两文中进行介绍,下面介绍第3种和第4种。

HandlerThread

HandlerThread继承了Thread,它是一种可以使用Handler的Thread,它通过在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环,这样在实际的使用中就允许在HandlerThread中创建Handler了。
public class HandlerThread extends Thread {}
HandlerThread的run方法如下:
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}
HandlerThread与普通Thread不同之处在于HandlerThread在内部创建了一个消息队列,外界需要通过通过Handler的消息方式来通知HandlerThread去执行一个具体的任务。
HandlerThread的具体使用场景有IntentService,由于HandlerThread的run()方法是一个无限循环,因此当不需要使用HandlerThread的时候,可以通过他的quit或者quitSafety方法来终止线程循环

IntentService

IntentService 是继承自 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,当任务执行完后,IntentService 会自动停止。
如果启动 IntentService 多次,那么每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,执行完自动结束。
同时由于IntentService是服务的原因,这导致它的优先级比单纯的线程要高很多,不容易被系统杀死,所以IntentService比较适合执行一些高优先级的后台任务。
public abstract class IntentService extends Service
在实现上IntentService封装了HandlerThread和Handler,这一点体现在它的onCreate()方法上
public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
IntentService第一次启动时,它会创建一个 HandlerThread,然后使用它的Looper来构造一个Handler对象mServiceHandler ,这样通过mServiceHandler发送的消息最终都会在HandlerThread中执行,从这个角度看,IntentService也适用于执行后台任务。

Android线程池

线程池的好处:
  1. 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
  2. 能有效控制线程池的最大并发数,避免大量的线程之间互相因抢占系统资源而导致的阻塞现象。
  3. 能够对线程进行简单的管理,并提供定制执行以及指定间隔循环执行等功能。
Android中的线程池的概念来源于Java中的Executor,Executor是一个接口,真正的线程池的实现为ThreadPoolExecutor。ThreadPoolExecutor提供了一系列的参数来配置线程池,通过不同的参数可以配置不同的线程池。

ThreadPoolExecutor

ThreadPoolExecutor是线程池的真正实现,我们通过ThreadPoolExecutor的构造函数来配置特定的线程池,其构造方法如下
public ThreadPoolExecutor(int corePoolSize,//核心线程数,默认情况会一直存活
                          int maximumPoolSize,//线程池所能容纳的最大线程数,当达到这个数后,后续任务会被阻塞
                          long keepAliveTime,//非核心线程闲置时的超时时长,超过时间会被回收
                          TimeUnit unit,//用于指定超时时长的单位,枚举
                          BlockingQueue<Runnable> workQueue) //线程池中的任务队列,通过线程池的execu方法提交的runnable对象会存储在这个参数中
			  ThreadFactory threadFactory){//线程工程,为线程池提供创建新线程的功能
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
            Executors.defaultThreadFactory(), defaultHandler);}
注意:当allowCoreThreadTimeOut属性被设置为true的时候,核心线程和非核心线程一样在闲置时有超时策略

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

ThreadPoolExecutor参数的配置在AsyncTask中有明显体现,下面是AsyncTask中的线程池的配置情况
//CPU核心数
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
 //核心线程数 = CPU核心数 -1 与 4 中取一个最小值 这个最小值与2之间去最大值,最终核心线程数的范围为【2,5】 private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    //线程池最大线程数 = CPU核心数的2倍 + 1
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    //超时设置为30S
    private static final int KEEP_ALIVE_SECONDS = 30;

    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;

    static {
        //默认超时单位为秒,TimeUnit.SECONDS
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        //核心线程有超时机制
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

线程池的分类

下面介绍Android中最常见的4类具有不同功能特性的线程池,他们都是通过直接或间接地配置ThreadPoolExecutor来实现自己的功能特性。

1. FixThreadPool

通过Executors的newFixedThreadPool方法来创建。它是一种线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池被关闭了。它只有核心线程,没有非核心线程。
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>());
}

2. CachedThreadPool

通过Executors的newCachedThreadPool方法来创建。它是一种线程数量不定的线程池,它只有非核心线程,并且最大值是Integer.MAX_VALUE,相当于可以任意大。
当有新任务的时候,有空闲线程就会调用空闲线程执行,没空闲线程就会创建新的线程,超时机制为60S。
它适合执行大量耗时较少的任务。
当整个线程池都处于闲置状态时,线程池中的所有线程都会因为超时而被停止,这时候线程池里没有任何线程,几乎不占用任何系统资源。
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
            60L, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());
}

3. ScheduledThreadPool

通过Executors的newScheduledThreadPool方法来创建。它的核心线程数是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立刻回收。
ScheduledThreadPool这类线程池主要用于执行定时任务和具有固定周期的重复任务。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
        int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

4. SingleThreadExecutor

通过Executors的newSingleThreadExecutor方法来创建。它内部只有1个核心线程,它确保所有的任务都在同一个线程中按顺序执行。它的意义在于统一所有外界任务到一个线程中,从而使这些任务之间不需要处理线程同步问题。
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>()));
}







  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值