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

概述

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

研究这些类以及开源框架的实现,可让咱们更好地理解并发编程,甚至是本身也能够写一个异步框架也不是什么难事,下面就来从源码的角度按照顺序来先分析一下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()方法必须首先被调用。bash

看过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;
    }
复制代码

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

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

获取子线程的Looperoop

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(),如今具体分析一下这两个方法的区别post

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

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

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的消息队列中的,因此是串行的,因此只适合并发量较少的耗时操做。

相关文章
相关标签/搜索