Android进阶(11)| 线程和线程池

作者: yzbkaka | 来源:发表于2019-05-30 19:28 被阅读8次
    本节目录

    一.主线程和子线程

    主线程:主线程在Android中也叫做UI线程主线程的作用是运行四大组件以及处理它们与用户的交互。在默认情况下一个进程只有一个线程,而这个线程就是主线程。

    子线程:子线程的作用就是执行耗时任务,比如网络请求,I/O操作等。从Android 3.0开始系统要求网络访问操作必须要在子线程完成,否则将会抛出异常。

    二.Android中线程的形态

    除了传统的Thread以外,线程还有AsyncTask、HandlerThread和IntentService这三种特殊的形态,这三者的底层实现也是线程,只不过是具有特殊的表现形式,下面来分别介绍:

    1.AsyncTask

    概念:AsyncTask是一种封装了Thread和Handler的轻量级异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。同时AsyncTask是一个抽象的泛型类,它的定义如下:

    public abstract class AsyncTask<Params,Progress,Result>
    

    内部方法:在AsyncTask中提供了5种核心的方法,如下所示:

    • onPreExecute()
      在主线程中执行,在异步任务执行之前此方法会被调用,一般可以做一些准备工作。

    • doInBackground(Params...params)
      在线程池中执行,此方法用于执行异步任务,params表示异步任务的输入参数。此方法可以通过publishProgress方法来更新任务进度。此外此方法需要返回计算结果给onPostExecute方法。

    • onProgressUpdate(Progress...values)
      在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。

    • onPostExecute(Result result)
      在主线程中执行,在异步任务执行之后,此方法会被调用,其中result参数是后台任务的返回值,即doInBackground方法的返回值。

    • onCancelled()
      在主线程中执行,当异步任务被取消时,onCancelled()方法会被调用。当该方法被调用后onPostExecute不会被调用。

    工作原理:当我们新建了一个AsyncTask对象之后,就可以使用execute方法来进行执行,同时在execute中又会去调用executeOnExecutor方法,在该方法中会去调用onPreExecute()方法,接着会去开启一个sDefaultExecutor的串行的线程池,在线程池中会去调用mWorker的call方法,而在call方法中会去调用postResult方法,在postResult方法中会通过sHandler发送了一个MESSAGE_POST_RESULT的消息,当sHandler收到MESSAGE_POST_RESULT这个消息后会调用AsyncTask的finish方法,该方法的具体实现如下:

    private void finish(Result result){
        if(isCancelled()){
            onCancelled(result);
        }
        else{
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
    

    2.HandlerThread

    概念:HandlerThread继承了Thread,它是一种可以使用Handler的Thread,在它的内部会进行Looper的创建以及开启。

    内部实现:Handler的实现也很简单,就是在run方法中通过Looper.prepared()来创建消息队列,并通过Looper.loop()来开启消息循环,具体实现如下:

    public void run(){
        mTid = Process.myTid();
        Looper.prepare();
        synchronized(this){
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    

    3.IntentService

    概念:IntentService是一种特殊的Service,它继承了Service并且是一个抽象类。IntentService可用于执行后台耗时的任务,同时由于IntentService是一个服务的原因使得它的优先级比单纯的线程要高出很多。

    工作流程:当IntentService被第一次启用时,它的onCreate()方法会被调用,在onCreate()方法中会创建一个HandlerThread。每次启动IntentService,它的onStartCommand方法就会被调用一次,IntentService在onStartCommand中处理每个后台任务Intent,onStartCommand()方法会调用onStart(),具体如下:

    public void onStart(Intent intent,int startId){
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
    

    在onStart()方法中会给mServiceHandler发送一条消息,当mServiceHandler接受到消息之后就会将Intent对象传递给onHandleIntent方法去处理,ServiceHandler的实现如下:

    private final class ServiceHandler extends Handler{
        public ServiceHandler(Looper looper){
            super(looper);
        }
    
        @Override
        public void handleMessage(Message msg){
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);  //执行结束,停止服务
        }
    }
    

    上述代码中onHandleIntent是一个抽象方法,它需要我们在子类中去实现,它的作用是从Intent参数中区分具体的任务并去执行这些任务。关于stopSelf方法,它会在最后一个任务执行完成之后才会去停止服务。

    三.Android中的线程池

    概念:线程池简单来说就是会缓存一定数量的线程,通过线程池就可以避免因为频繁创建和销毁线程所带来的系统开销。Android中线程池的概念来源于Java中的Executor,它是一个接口,它的真正实现是ThreadPoolExecutor,ThreadPoolExecutor提供了一系列参数来配置线程池,通过不同的参数可以创建不同的线程池。

    1.ThreadPoolExecutor

    构造方法:ThreadPoolExecutor的构造方法提供了一系列参数来配置线程池,它的构造方法定义如下:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory)
    
    • corePoolSize
      线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使它们处于闲置状态。如果将ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,那么当延时超过keepLiveTime之后,核心线程就会被终止。

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

    • keepLiveTime
      默认为非核心线程闲置超时时长,超过这个时长,非核心线程就会被回收。

    • unit
      用于指定keepLiveTime参数的时间单位,这是一个枚举。

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

    • threadFactory
      线程工厂,为线程池提供创建新线程的功能。ThreadFactory是一个接口,它只有一个方法:Thread newThread(Runnable r);

    2.ThreadPoolExecutor执行规则

    (1)如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。
    (2)如果线程池中的线程数量达到核心线程的数量,那么任务会被插入到任务队列中排队等待执行。
    (3)如果在(2)中无法将任务插入到任务队列中,这时就是任务队列已满,这时如果线程数量未达到线程池所规定的最大值,那么就会启用一个非核心线程来执行任务。
    (4)如果线程数量已经达到了线程规定池规定的最大值,那么就会拒绝执行此任务。

    3.线程池的分类

    1.FixedThreadPool
    它是一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收。当所有的线程都处于活动状态时,新任务都会处于等待状态。FixedThreadPool只有核心线程并且这些核心线程都不会被回收,因此它能够更快的相应外界的请求。

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

    2.CachedThreadPool
    该类线程是一种数量不定的线程池,它只有非核心线程,而它内部的最大线程数可以近似于任意大,而它内部对空闲线程有超时机制,并且超时时长为60s,超过时间线程就会被收回。由于这些特性,可以得到该线程内部的任务队列其实相当于一个空集合,这将导致任何任务都会被立即执行。该类线程比较适合执行大量的耗时较少的任务。

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

    3.ScheduleThreadPool
    该类线程的核心数量是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立即回收。该线程池主要用于执行定时任务和具有固定周期的重复任务。

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

    4.SingleThreadExecutor
    该类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadExecutor的意义在于统一所有外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题。

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

    相关文章

      网友评论

        本文标题:Android进阶(11)| 线程和线程池

        本文链接:https://www.haomeiwen.com/subject/ggqvtctx.html