Android的HandlerThread的源码分析

1、简介

HandlerThread顾名思义,就是Thread与Handler相结合,其本质还是一个线程,只是在该线程中添加了该线程相关的Handler,实现了轻量级的异步类,具有以下特点:

  • 普通线程类:与普通线程的使用类似,需要通过新建线程对象并调用start()开启线程;
  • 内部嵌套了Handler:包含与该线程相绑定的Handler,方便线程之间的数据交互;
  • 串行运行:其内部通过Looper实现任务的串行阻塞队列。

2、简单使用

2.1 作为线程使用

相比普通的线程,HandlerThread有一大优势就是在该类中可以创建工作Handler对象,在异步任务结束后,发送至工作区的Handler的handleMessage中,而如果普通的线程需要自己手动的维持Looper的prepare()和loop()方法。

//1、创建和执行MYHandlerThread 类,添加线程名称
MYHandlerThread myHandlerThread = new MYHandlerThread("xiaohan");
myHandlerThread.start();

class MYHandlerThread extends HandlerThread {
        public MYHandlerThread(String name) {
            super(name);
        }
//2、重写onLooperPrepared()方法
        @Override
        protected void onLooperPrepared() {
            super.onLooperPrepared();
 //执行耗时任务
            SystemClock.sleep(3 * 1000);
//3、任务结束,将结果发送至工作区的Handler中
            Message message = subHandler.obtainMessage();
            message.what = 101;
            message.obj = "finsh";
            subHandler.sendMessage(message);
        }
//4、创建工作区中的Handler 接收异步任务的处理结果
        Handler subHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                String result = (String) msg.obj;
                Log.i(TAG, "handleMessage: 子线程中的Handler  " + result);
            }
        };
    }
//5、结束线程
mHandlerThread.quit();

2.2 作为“线程池”使用

//1、创建HandlerThread,添加线程名称
 mHandlerThread = new HandlerThread("xiaohan");
//2、开启HandlerThread线程
 mHandlerThread.start();
//3、创建WorkHandle工作区,处理不同的异步任务
mWorkHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case UPDATE_THREAD1:
                        Log.i(TAG, "handleMessage: 子线程处理任务1");
                        break;
                    case UPDATE_THREAD2:
                        Log.i(TAG, "handleMessage: 子线程处理任务2");
                        break;
                }
            }
 };
Message message = mWorkHandler.obtainMessage();
message.what = UPDATE_THREAD1;
message.obj = num + "";
 mWorkHandler.sendMessage(message);
//4、结束线程
mHandlerThread.quit();

简要说明:

  • 创建HandlerThread对象:创建HandlerThread对象,填写线程名称,通过start()启动该线程;
  • 创建工作区Handler:通过getLooper()获取当前线程的Looper对象,在创建Handler时与其绑定,从而该Handler持有了Looper以及MessageQueue,正常工作。
  • 发送异步任务:根据需要发送异步的Message 信息至工作区的handleMessage中,进行耗时操作。

3、源码分析

源码的分析,参考第二部分中使用的步骤,可以看出以上两种方式都大致分为5步。下面参考2.2中的执行流程分析如下:

3.1 创建HandlerThread,添加线程名称

HandlerThread的构造方法如下:

//线程优先级
int mPriority;
//线程号
int mTid = -1;
//Looper对象
 Looper mLooper;
 //Handler 对象
private @Nullable Handler mHandler;
//只包含线程名称的构造,其默认线程优先级为默认的:0
public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
//包含线程名称和优先级的构造  
public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

本部分主要是新建HandlerThread类,设置进程名称和优先级。

3.2 开启HandlerThread线程

调用start()后开始执行线程的run方法,如下所示:

 @Override
    public void run() {
    //获取线程号
        mTid = Process.myTid();
     //调用prepare()方法,准备MessageQueue
        Looper.prepare();
      //阻塞等待,查看Looper是否准备完成,其notifyAll()主要针对下面的getLooper()中的wait()方法
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
      //设置线程优先级
        Process.setThreadPriority(mPriority);
       //自定义时,重写该方法,实现异步操作
        onLooperPrepared();
        //开启loop循环
        Looper.loop();
        mTid = -1;
    }
  • 针对开启线程后,主要完成Looper的准备、阻塞和开启;
  • 提供自定义重写onLooperPrepared()方法调用;
  • 开启loop,执行消息的存储和派发
3.3 创建WorkHandle工作区,处理不同的异步任务
mWorkHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case UPDATE_THREAD1:
                        Log.i(TAG, "handleMessage: 子线程处理1");
                        break;
                    case UPDATE_THREAD2:
                        Log.i(TAG, "handleMessage: 子线程处理2");
                        break;
                }

            }
        };
  • 创建Handler:获取HandlerThread的Looper对象,将其与工作Handler相绑定;
  • 重写handleMessage方法:由于WorkHandler与HandlerThread的线程相绑定,因此其handleMessage是运行在其子线程中;

熟悉Handler的都知道,在子线程中调用Handler时,必须要与Looper相绑定,否则无法获取MessageQueue和执行loop()方法,那如何保证在运行工作区Handler时Looper对象已经准备好?

解决方案如下:

@Override
    public void run() {
		...
		//1、开始准备Loop
		Looper.prepare();
		//2、阻塞准备,加锁准备
		synchronized (this) {
		//3、Looper准备完成,取消阻塞等待,发送通知,释放锁
            mLooper = Looper.myLooper();
            notifyAll();
        }
        ...
}

 public Looper getLooper() {
			...
			synchronized (this) {
			//4、等待Looper是否准备完成
            		while (isAlive() && mLooper == null) {
               				 try {
                 				   wait();
               				 } catch (InterruptedException e) {
                }
			...
			//5、发送Looper对象
			return mLooper;
}

主要流程如下:

  • 准备Looper:通过Looper.prepare(),开始准备Looper对象;
  • 阻塞等待:加锁(synchronized ),去准备Looper对象,准备完成后开始通知释放锁;
  • 完成Looper的获取:在通过getLooper()时,一直加锁等待Looper的准备完成,直至 notifyAll()释放锁,因此在getLooper()时确保Looper准备完成。

完成工作区Handler后就可以根据需要发送消息至其handleMessage中,执行异步的任务处理

3.4 结束线程

调用HandlerThread的quit()方法,结束线程,查看源码可以发现其线程的结束包括两个方法:quit()和quitSafely(),其中:quit()线程不安全,quitSafely()是线程安全的。如果需要线程安全,其肯定会引起执行效率降低。

//HandlerThread
 public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    
public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

对比两个方法可以看出,其执行线程结束主要是借助Looper 的quit()和quitSafely()方法,而Looper中时对MessageQueue的quit赋值true或者false控制。

//Looper 
public void quit() {
        mQueue.quit(false);
    }
public void quitSafely() {
        mQueue.quit(true);
    }
//MessageQueue
void quit(boolean safe) {
...
//判断是否为线程安全
		 if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }
...
}
//移除所有消息 线程不安全
//遍历所有消息,并置空
 private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }
//移除所有消息 线程安全    
private void removeAllFutureMessagesLocked() {
        final long now = SystemClock.uptimeMillis();
	  Message p = mMessages;
        if (p != null) {
            if (p.when > now) {
                removeAllMessagesLocked();
            } else {
		....
	}
}	

简要说明
区分:从HandlerThread–Looper --MessageQueue可以看出,最终区分是否安全是对于MessageQueue中的quit方法,而查看其源码可以看出,线程安全的处理是在回收消息时,判断消息的时间,如果该消息未处理完成则等待处理,否则直接处理(与线程不安全类似)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值