Android多线程之HandlerThread详解
发布日期:2021-05-06 20:20:19 浏览次数:26 分类:原创文章

本文共 3841 字,大约阅读时间需要 12 分钟。

一 HandlerThread介绍

当系统中有多个耗时任务需要执行时,每个任务都会开启一个新线程去执行耗时任务,这样会导致系统多次创建和销毁线程,从而影响性能。为了解决这一问题,Android 提供了 HandlerThread,HandlerThread 是在线程中创建一个 Looper 循环器,让 Looper 轮询消息队列,当有耗时任务进入队列时,则不需要开启新线程,在原有的线程中执行耗时任务即可,否则线程阻塞。

二 工作原理

  • HandlerThread 继承 Thread,在 Thread 开始执行时跟主线程在 ActivityThread.main() 方法内执行代码逻辑类似,初始化 Looper–Looper.prepare(),轮询消息–Looper.loop()
  • 初始化 Handler 时,使用 HandlerThread 线程的 Looper 对象初始化---- new Handler(Looper) 构造方法
  • 至于为什么是在子线程内执行是因为此 Handler 使用的 Looper 是子线程创建的,执行 message.target.dispatchMessage() 也在子线程内,所以最终执行的 Runnable 或者 handleMessage() 也会在子线程内。

三 实例代码

  // 步骤1:创建HandlerThread实例对象  // 传入参数 = 线程名字,作用 = 标记该线程  HandlerThread mHandlerThread = new HandlerThread("handlerThread");  // 步骤2:启动线程  mHandlerThread.start();  // 步骤3:创建工作线程Handler & 复写handleMessage()  // 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与 其他线程进行通信  // 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行  Handler workHandler = new Handler( handlerThread.getLooper() ) {               @Override            public boolean handleMessage(Message msg) {                   ...//消息处理                return true;            }        });  // 步骤4:使用工作线程Handler向工作线程的消息队列发送消息  // 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作  // a. 定义要发送的消息  Message msg = Message.obtain();  //消息的标识  msg.what = 1;  // b. 通过Handler发送消息到其绑定的消息队列  workHandler.sendMessage(msg);// 步骤5:结束线程,即停止线程的消息循环  mHandlerThread.quit();

四 源码分析

4.1 实例化HandlerThread

public class HandlerThread extends Thread {       int mPriority;    int mTid = -1;    //当前线程持有的Looper对象    Looper mLooper;    private @Nullable Handler mHandler;    // 方式1. 默认优先级    public HandlerThread(String name) {           // 通过调用父类默认的方法创建线程        super(name);        mPriority = Process.THREAD_PRIORITY_DEFAULT;    }    // 方法2. 自定义设置优先级    public HandlerThread(String name, int priority) {           super(name);        mPriority = priority;    }    ......}

4.2 启动HandlerThread

    @Override    public void run() {           // 1. 获得当前线程的id        mTid = Process.myTid();        // 2. 创建1个Looper对象 & MessageQueue对象        Looper.prepare();        // 3. 通过持有锁机制来获得当前线程的Looper对象        synchronized (this) {               mLooper = Looper.myLooper();            // 发出通知:当前线程已经创建mLooper对象成功            // 此处主要是通知getLooper()中的wait()            notifyAll();        }        // 4. 设置当前线程的优先级        Process.setThreadPriority(mPriority);        // 5. 在线程循环前做一些准备工作        // 该方法实现体是空的,由子类决定是否实现        onLooperPrepared();        // 6. 进行消息循环,即不断从MessageQueue中取消息 & 派发消息        Looper.loop();        mTid = -1;    }

run() 内所做操作和 ActivityThread.main() 方法内所操作的东西大体相类似。不同的是,利用了锁机制来保证 getLooper() 获取 looper 正确。

4.3 获取实例化Handler要用到的Looper

    public Looper getLooper() {           // 若线程不是存活的,则直接返回null        if (!isAlive()) {               return null;        }         // 若当前线程存活,再判断线程的成员变量mLooper是否为null        // 直到线程创建完Looper对象后才能获得Looper对象,若Looper对象未创建成功,则阻塞        synchronized (this) {                     while (isAlive() && mLooper == null) {                   try {                       // 此处会调用wait方法去等待                    wait();                } catch (InterruptedException e) {                   }            }        }        // 上述步骤run()使用 持有锁机制 + notifyAll()  获得Looper对象后        // 则通知当前线程的wait()结束等待 & 跳出循环        // 最终getLooper()返回的是在run()中创建的mLooper对象        return mLooper;    }
  • 在获得 HandlerThread 工作线程的 Looper 对象时存在一个同步的问题:只有当线程创建成功 & 其对应的 Looper 对象也创建成功后才能获得 Looper 的值,才能将创建的 Handler 与 工作线程的 Looper 对象绑定,从而将 Handler 绑定工作线程
  • 解决方案:即保证同步的解决方案 = 同步锁、wait() 和 notifyAll(),即 在 run() 中成功创建 Looper 对象后,立即调用 notifyAll()通知 getLooper() 中的 wait()结束等待 & 返回 run() 中成功创建的 Looper 对象,使得 Handler 与该 Looper 对象绑定

五 总结

  • HandlerThread 本质上是一个线程类,它继承了 Thread
  • HandlerThread 有自己的内部 Looper 对象,可以进行 looper 循环
  • 通过获取 HandlerThread 的 looper 对象传递给 Handler 对象,可以在 handleMessage 方法中执行异步任务
  • 创建 HandlerThread 后必须先调用 HandlerThread.start() 方法,Thread 会先调用 run 方法,创建 Looper 对象
上一篇:Android多线程之IntentService详解
下一篇:Android 消息机制底层原理

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年04月03日 20时40分58秒