阅读 306

并发编程(6)HandlerThread源码分析

概述

前面分析了很多并发编程方面的东西,但是都是Java层面的,其实Google原生也提供了一些类方便我们进行并发编程,比较常见的有HandlerThreadIntentServiceAsyncTask,除此之外还有一些第三方框架VolleyPicasso等。

研究这些类以及开源框架的实现,可以让我们更好地理解并发编程,甚至是自己也可以写一个异步框架也不是什么难事,下面就来从源码的角度按照顺序来先分析一下HandlerThread

正文

注释

Handy class for starting a new thread that has a looper. The looper can then be 
used to create handler classes. Note that start() must still be called.
复制代码

一个好用的类用于创建一个自带Looper的线程。这个Looper可以用来创建Handler。注意start()方法必须首先被调用。

看过Handler的源码都应该比较熟悉,Handler的消息是需要Looper来进行轮询的,也就是每个Handler创建的时候都需要传入一个Looper,不过我们平时创建Handler的时候之所以不需要传入Looper,是因为主线程默认为我们创建了一个looper,当然我们也可以传入自己的Looper.所以为了避免每次在子线程中创建Handler都需要创建Looper,Google为我们提供了HandlerThread这个类。

成员变量

    int mPriority;//线程优先级
    int mTid = -1;//线程ID
    Looper mLooper;//创建线程的Looper
复制代码

继承关系

HandlerThread

继承关系比较简单,仅仅继承自Thread,在内部做了一些封装。

构造方法

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
复制代码

这个方法Google都没有注释,太简单了,就是传入一个线程名称,然后优先级是默认的优先级0

  public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
复制代码

构造方法中新加了一个线程优先级

run方法


    @Override
    public void run() {
        //获取进程ID
        mTid = Process.myTid();
		//Loopr准备
        Looper.prepare();
        //创建Looper
        synchronized (this) {
            mLooper = Looper.myLooper();
          //唤醒所有等待的线程
            notifyAll();
        }
        //设置线程优先级
        Process.setThreadPriority(mPriority);
      	//在Looper循环时做一些准备工作
        onLooperPrepared();
        //开启循环
        Looper.loop();
        mTid = -1;
    }
复制代码

getLooper

获取子线程的Looper

  public Looper getLooper() {
       //如果线程已经消亡,就返回null
        if (!isAlive()) {
            return null;
        }
        //如果线程已经创建了,就在此处停留等待Looper创建完成之后
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                  //等待线程被创建
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
复制代码

quit方法

   public boolean quit() 
     	//获取looper
        Looper looper = getLooper();
		//退出looper
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
复制代码

quitSafely

   public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }
复制代码

跟quit方法的唯一区别在于looper.quit()变成了looper.quitSafely(),现在具体分析一下这两个方法的区别

    public void quit() {
        mQueue.quit(false);
    }
    
    public void quitSafely() {
        mQueue.quit(true);
    }
复制代码

一个传入了false,一个传入了true,继续追踪

  void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
              //移除消息队列中延迟的消息
                removeAllFutureMessagesLocked();
            } else {
              //移除消息队列中所有的消息
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }
复制代码

removeAllFutureMessagesLocked方法

   private void removeAllFutureMessagesLocked() {
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            if (p.when > now) {
              	//当消息队列中中的消息的发送时间大于当前时间
        		//就移除该消息
                removeAllMessagesLocked();
            } else {
                Message n;
                for (;;) {
                    n = p.next;
                    if (n == null) {
                        return;
                    }
                    if (n.when > now) {
                        break;
                    }
                    p = n;
                }
                p.next = null;
                do {
                    p = n;
                    n = p.next;
                    p.recycleUnchecked();
                } while (n != null);
            }
        }
    }
复制代码

所以看到这里,quit跟quidSafely的区别就在于是否移除消息队列中还未发送也就是延迟的消息。

使用

       //创建mHandlerThread
        mHandlerThread = new HandlerThread("main");
        //获取HandlerThead中的Looper
        Looper looper = mHandlerThread.getLooper();
        //创建子线程中的Looper
        Handler handler = new Handler(looper);
        //执行耗时操作
        handler.post(new Runnable() {
            @Override
            public void run() {
                //子线程中执行耗时操作
            }
        });
        
        
   //界面销毁的时候需要销毁Looper
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
    }
复制代码

总结

如果没有HandlerThread,我们需要手动去创建一个线程,现在HandlerThread可以帮我们简化这个操作,但是有一点需要注意的是,由于我们的异步操作是存放在Handler的消息队列中的,所以是串行的,所以只适合并发量较少的耗时操作。

关注下面的标签,发现更多相似文章
评论