首页 > 代码库 > HandlerThread的研究

HandlerThread的研究

一、概述:
     顾名思义,它实际上仍然是一个Thread,只不过这个Thread比较特殊,它内部包含了一个Looper对象。这个Looper对象可以被用来创建一个Handler,在创建Handler对象之前,必须要先调用该Thread的start()方法。


二、实现原理:
     1.为什么在构造Handler对象之前,必须得先调用Thread的start()方法?
     从源码上看该Thread的run()方法实现
    
      public void run() {
          ……
          …...          
          Looper.prepare();                              //创建该线程相关联的Looper对象
          synchronized(this) {                          //这里为什么要加锁呢?
               mLooper = Looper.myLooper();     //获取该线程相关的Looper对象
               notifyAll();                                   //通知所有等待该线程Looper对象的其他子线程,本线程的                    
                                                                 //Looper对象已就绪  
          }
          ……
          …...
          onLooperPrepared();
          Looper.loop();                                   //开始进行消息循环
          ……
          …...
     }
     
     为什么要先调用start()方法,从这里可以看到,在线程开始执行后,会自动创建一个与该线程相关联的Looper对象,如果在创建Handler对象之前没有start线程,则是获取不到Looper对象的。

     2.线程里为什么要加锁呢?
     这就要看getLooper()方法的实现了

     public Looper getLooper() {
          if(!isAlive()) {               //如果该线程不是活着的,则返回null
               return null;
          }
          synchronized(this) {
               while(isAlive() && mLooper == null) {
                    try {
                         wait();
                    } catch(InterruptedException e) {
                    }
               }
          }
          return mLooper;
     }

     因为创建Handler对象需要提供一个Looper对象作为参数,所以HandlerThread类提供了getLooper()方法,来直接获取与该线程关联的Looper对象。
     首先在线程还没有start(),或者线程已经死亡,或者线程的run()方法已经执行完毕退出,直接返回null,因为这个时候该线程不能执行任何任务,是没有意义的。
     接下来,当线程处在alive状态时,如果发现mLooper对象一直为空,则一直wait(),直到Looper对象已经被创建,并且mLooper变量已经赋值后,才能退出。
     HandlerThread t = new HandlerThread("Test");
     t.start();
     mHandler = new MyHandler(t.getLooper());
     以上为一般HandlerThread的使用方法,可见在t线程start()之后,为了创建Handler对象,立马调用了t线程的getLooper()方法,这个时候,t线程的run()方法执行到哪个步骤并不确定:可能Looper对象还没创建,可能Looper对象已经创建,可能Looper对象已经创建完毕,但是mLooper变量值依旧为空。如果当调用getLooper()方法时,mLooper变量为空,则执行getLooper()方法的线程会一直wait,直到Looper对象在t线程的run()方法中被创建,并且mLooper变量已经有值时,才会被唤醒。
     
     3.退出
     在程序退出,或者不需要使用的时候,需退出消息循环,否则该线程会一直占用系统资源,造成浪费。如果没有消息发送,则Looper内部的MessageQueue会一直循环等待,该线程一直不会结束。
     public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    

三、总结
     1.实质上仍旧是个Thread,不同于普通的Thread在于它内部有个Looper对象,可以进行消息循环;
     2.为什么需要HandlerThread,而不使用普通的Thread呢。当我们需要一个工作者线程,而不把它当做一次性消费品,用过即废弃的话,就可以使用它。使用场景如:当我们需要反复使用线程做某个事情时,如果每次都创建一个Thread,会造成资源过度的开销,毕竟创建线程是很费系统资源的,这个时候就可以采用HandlerThread来做了。它内部有一个消息队列,没消息时会wait,有消息时,会被唤醒处理任务,整个过程中,我们只需要创建一个Thread来做完这么多事情,会节省资源。




HandlerThread的研究