网站首页> 后端开发> Java> Java Handler同步屏障浅析讲解

Java Handler同步屏障浅析讲解

时间:2022-08-29 10:25:36 阅读:216次 来源:互联网

1.在View的加载和绘制流程这篇文章中:传送门,有一个编舞者类,mChoreographer。 

mTraversalBarrier = mHandler.getLooper().postSyncBarrier();向MessageQueue中插入一条同步屏障消息,msg.target==null的消息,返回值mTraversalBarrier是一个int 的token值。

  void scheduleTraversals() {
    if (!mTraversalScheduled) {
      mTraversalScheduled = true;
       //向消息队列插入一个同步屏障的消息。msg.target==null的消息
             mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
             mChoreographer.postCallback(
                  Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
  }

mChoreographer.postCallback()方法会执行mTraversalRunnable中的代码。

mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);这个会根据上面产生的token值移出MessageQueue中的同步屏障消息。

 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
 final class TraversalRunnable implements Runnable {
            @Override
            public void run() {
                doTraversal();
            }
  }
   void doTraversal() {
      if (mTraversalScheduled) {
          mTraversalScheduled = false;
          //移除同步屏障消息
          mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
          //在这个方法中会调用 measure layout draw,view的绘制绘制流程的方法
          performTraversals();
      }
    }

还是看这行代码mHandler.getLooper().postSyncBarrier(),系统是怎么处理的。

获取了一个没有设置handler的Message。

int enqueueSyncBarrier(long when) {
        // Enqueue a new sync barrier token.
        // We don't need to wake the queue because the purpose of a barrier is to stall it.
        synchronized (this) {
            final int token = mNextBarrierToken++;
            // 这个msg.target没有被赋值
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            msg.arg1 = token;
            Message prev = null;
            Message p = mMessages;
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            if (prev != null) { // invariant: p == prev.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }

正常我们通过handler发送消息,handler是不允许为空的。

 boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
   ...........
}

那系统为啥要发送一个handler为空的消息呢?

先看mChoreographer发了同步屏障消息后,又做了什么?

又发送了一个异步消息:msg.setAsynchronous(true),这个消息的handler不为null。

private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
      synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                //将消息设置为异步消息
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
}

接下来看看MessageQueue是怎么去消息的,是如何对这个同步屏障消息怎么处理的。

 Message next() {
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                //如果msg.target==null说明我们已经向消息队里中插入了一条屏障消息。
                //此时会进入到这个循环中,找到msg.isAsynchronous==true的异步消息。
                //通常我们发送的都是同步消息isAsynchronous = false的,并且msg.target不能为null的。
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());//msg.isAsynchronous==true时结束循环,说明找到了这个异步消息。
                }
                if (msg != null) {//找到了同步屏障的异步消息后,直接返回
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        return msg;
                    }
                } else {//没有找到的话则进入休眠直到下一次被唤醒
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
        }
    }

在取消的时候,先判断进行msg.target为null的判断,然后经过while循环,找到msg.isAsynchronous() == true的消息。也就是上面发送的异步消息。通常我们发送的消息都是同步消息,不会对对 msg.setAsynchronous(true);进行设置。

系统这样做的目的就是为了优先去处理这个异步消息。会把所有的同步消息放在后面,向一道屏障一样,所以这样的操作,被称为同步屏障,是同步屏障消息的处理有更高的优先级。

因为编舞者类mChoreographer 负责屏幕的渲染,需要及时的处理从底层过来的信号,以保障界面刷新的频率。

那么mChoreographer是如何处理信号的,如何进行渲染的逻辑是怎么样的,有机会再写文章进行分享。

本文地址:https://www.manongw.com/article/387.html

文章来源:转载于CSDN,转载网址为https://blog.csdn.net/niuyongzhi/article/details/125982305

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

相关文章
  • 本文主要介绍了IDEA创建Servlet并配置web.xml的实现的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-10-23 10:52
  • 本文主要介绍了Java Servlet请求重定向的方法的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-11-10 16:09
  • 本文主要介绍了史上最通俗理解的Java死锁代码演示的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-10-19 22:27
  • 本文主要介绍了Spring如何基于aop实现操作日志功能的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-11-10 10:29
  • 本文主要介绍了springboot整合dubbo设置全局唯一ID进行日志追踪的示例代码的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-10-26 18:52
  • 本文主要介绍了Java Servlet 运行原理分析的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-11-10 16:31
  • 本文主要介绍了Kafka单节点伪分布式集群搭建实现过程详解的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-11-12 12:08
  • 本文主要介绍了关于Java8中map()和flatMap()的一些事的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-10-25 16:12
  • 本文主要介绍了Spring Cloud Alibaba 之 Nacos教程详解的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-11-06 19:59
  • 本文主要介绍了基于springboot实现文件上传的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...
    2020-11-09 09:24