深入理解HandlerThread

深入理解HandlerThread以往遇到HandlerThread,对它的认识只是停留在MessageLooperHandler上,知道它有自己的消息队列,仅此而已。随着编程的深入,个人已不再满足表面上的理解,所以再次翻开HandlerThread源码,做梳理记录。HandlerThread集成Thread,并重写了Thread类的run方法(如果我们自定义一个类继承HandlerThread,就用不到run函数了):

大家好,又见面了,我是你们的朋友全栈君。

以往遇到HandlerThread,对它的认识只是停留在Message<->Looper<->Handler上,知道它有自己的消息队列,仅此而已。随着编程的深入,表面上的理解无法满足要求,所以再次翻开HandlerThread源码,做梳理记录。

HandlerThread集成Thread,并重写了Thread类的run方法(如果我们自定义一个类继承HandlerThread,就用不到run函数了):

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

从图中我们可以看到,HandlerThread的run方法先后执行了Looper.prepare()、Looper.loop(),因为我们知道这样做的目的是为了给HandlerThread实例建立一个属于它的消息队列(MessageQueue,这一点像极了Windows系统的窗口消息分发机制)。

     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

Looper.loop()的工作就是开始不断的从消息队列中取出消息(在loop函数里有个for循环,除非线程被系统杀死或者被调用quit函数,负责for循环会一直执行)

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

有人说Looper中的sThreadLocal属性(ThreadLocal<Looper>类型)是个静态常量,怎么保证每个执行过Looper.prepare()、Looper.loop()的线程都有唯一的Looper呢?这个问题刚开始我也很好奇,后来发现原因在ThreadLocal类。

/**
 * Implements a thread-local storage, that is, a variable for which each thread
 * has its own value. All threads share the same {@code ThreadLocal} object,
 * but each sees a different value when accessing it, and changes made by one
 * thread do not affect the other threads. The implementation supports
 * {@code null} values.
 *
 * @see java.lang.Thread
 * @author Bob Lee
 */
public class ThreadLocal<T> 

上述类的解释是说ThreadLocal实现了线程的本地存储,即所有的线程共同使用同一个ThreadLocal对象,但每个线程都会有一个ThreadLocal对象副本,每个线程的ThreadLocal对象副本又是相互独立的,互不影响。

推荐一篇介绍ThreadLocal的博文,写的很不错:彻底理解ThreadLocal

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/157929.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 使用bootbox.js(二级务必提交书面和数字到数字中国)

    使用bootbox.js(二级务必提交书面和数字到数字中国)

    2022年1月3日
    44
  • 怎么算图中有多少个三角形_贪心算法经典例题

    怎么算图中有多少个三角形_贪心算法经典例题题目:请说出下面图形中包含多少个三角形?请用一个程序完成计算。C++版本解题思路:(1)给每个交点做标记,如下:(2)总共有36条线段,如果三条线段两两之间存在交点,但一条线上(已经包含了三条

    2022年8月1日
    6
  • 怎么查询自己的网站是否被挂马_被墙域名检测

    怎么查询自己的网站是否被挂马_被墙域名检测在我们日常seo优化工作当中,会经常碰到网站被挂马了,原因是我们很多都是用的常用的cms网站系统,如织梦、帝国等,这种网站程序都是开源的代码,所以就会有些漏洞,导致很多所谓刚入门的学习的所谓黑客们进行攻击,利用各种挂马检查工具进行攻击,导致我们的网站网页中有其他乱七八糟的页面,严重的首页打不开,后台没有权限打开等。那么接下来就为广大seo优化人员讲解一下,如果你网站被挂马了,如何检查出来,然后又如何进行防止被挂马,进行相应的措施,加强网站的安全维护。一**、那么,网站挂马检测工具有哪些呢?**1、第一种

    2022年9月30日
    3
  • 学习笔记-正则表达式[通俗易懂]

    学习笔记-正则表达式[通俗易懂]学习笔记-正则表达式

    2022年4月20日
    46
  • 大富豪3辅助器_加油站大亨作弊

    大富豪3辅助器_加油站大亨作弊   开心001最近新增加了一个功能:超级大亨,开始那几天没有外挂能进行操作,自己也很感兴趣,就动了编写一个外挂练习的念头。网上最早的一篇讲解开心网外挂的是http://www.turbozv.com/read.php/838.htm,写得很详细。   首先要分析下超级大亨的游戏赚钱手段:   1.每4小时登录本组件1次,将获得一定的资金奖励;   2.物品的市场价格会不断浮

    2025年9月4日
    5
  • java中创建数组的三种方法

    java中创建数组的三种方法publicstaticvoidmain(String[]args){ //创建数组的第一种方法 int[]arr=newint[6]; intintValue=arr[5]; //System.out.println(intValue); //创建数组的第二种方法 int[]x={1,2,3,4}; //System.out.println(x[1]); //…

    2022年6月7日
    29

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号