Android:从另一个线程向主线程发布runnable实际上做了什么?

时间:2015-12-07 00:57:11

标签: java android multithreading

所以,正如标题所说:当你将另一个线程的runnable发布到主线程上时会发生什么?

我已经看到很多问题,询问你是如何做到这一点的,以及它的基础知识是如何运作的。但是,当你在MessageQueue上放置一个runnable时,我很难找到确切的解释。肯定是它在Runnable转弯时运行。但这是什么时候?

所以例如:
假设有一个启动ASync请求的按钮,请求返回并触发在MainThread上运行的runnable / callback。怎么了? runnable被添加到MessageQueue并在'time'时运行。但是什么时候到了?如果我在Async请求发布MainThread上的runnable之前按下另一个在MainThread上执行半长阻塞任务的按钮怎么办?是否等到我的阻止按钮上的逻辑完成?它会打断它吗?它是否将可运行代码与我的阻塞代码按钮的代码交织在一起?究竟发生了什么?

我问的主要原因是,我可以更好地了解我需要考虑哪些因素来防止多线程导致的错误。 (特别是影响已刷新页面的旧请求的情况)

2 个答案:

答案 0 :(得分:4)

首先,您需要了解Message类是什么样的。 Message对象包含以下字段:

    Handler target;     // a handler that enqueued the message
    long when;          // the time at which the message is to be processed 

    [RUNNABLE] Runnable callback;   =
    [SWITCHED] int what, int arg1, int arg2, Bundle data...

    bool isAsynchronous; // I will talk about it in the end

我用 [RUNNABLE] [SWITCHED] 标记的内容代表处理Message的两种非重叠方式。如果callback不为空,则忽略所有 [SWITCHED] 字段。如果callback为空,而Message [SWITCHED] 字段定义,则会在Handler's覆盖handleMessage()或{使用。{/ p>初始化handleMessage()处理程序的{1}}

Handler.CallbackMessageQueue字段排序。在when衡量的当前时间大于或等于消息的Looper字段中存储的时间之前,SystemClock.uptimeMillis不会出列消息并处理消息。

当您致电when时,会发生以下情况:

  1. 从池中获取Handler#post(Runnable r)(一个简单的静态链表 在Message类)

  2. 您的Message被分配到邮件的Runnable字段。

  3. 如果没有延迟或具体,
  4. callback字段只是设置为当前时间 时间过去了

  5. when已加入Message。如果是MessageQueue 它比队列的头部更早成为一个新头。如果 它不是,而是插在中间,以便when 仍按MessageQueue

  6. 排序
  7. when处于非终止循环中的队列消息 从队列中按顺序处理它们(没有交织), 最终,我们的消息出列并致电Looper 最初发布dispatchMessage()

  8. 的处理程序
  9. 处理程序决定邮件是否为 [RUNNABLE] [SWITCHED] 并相应地处理它。特别是它打电话 Runnable上的run()(如果有)

  10. 这应该回答你关于在阻止任务期间发布在UI线程上的callback行为的问题 - 好吧,不,它不会中断正在进行的任务,也不会交织。首先在线程上发生的一切都会进入Runnable,按钮点击或您从其他线程发布的自定义MessageQueue。基本上没有办法以其他方式发生:Runnables只是让线程忙于其Looper.loop()循环。

    有很多方法可以更改订阅消息。

    例如,Looper / Handler框架中有一个有趣的同步屏障概念。一个惯例只是一个for(;;)同步障碍Message(所以它基本上只是一个类似于旗帜的东西,没有处理程序来调度它)。如果将其放入target的队列中,则整个队列的更改将更改,直到同步屏障从postSyncBarrier()的队列中删除。未标记为removeSyncBarrier()的{​​{1}}将被忽略,并且不会出列和处理。而是扫描队列,直到找到Messages的消息。然后根据其isAsynchronous进行安排,并在时机到来时进行处理。

    此外,您可以调用一个不言自明的isAsynchronous = true,但正如文档中所指出的那样

      

    此方法仅适用于非常特殊的情况 - 它可以   容易使消息队列饿死,导致排序问题,或者有   其他意想不到的副作用。

    我建议你浏览所提到的所有课程的source code。它读起来就像一本好书。

答案 1 :(得分:1)

MainThread执行了许多其他runnable,例如更新UI,触摸事件。 '时间'是发布的runnable准备好出列的时间。如果任何其他runnable出现在它之前,你的runnable将等待。

这里没有中断这样的事情。你的按钮将提交一系列runnables,就像从许多不同的线程中提交相同数量的runnable一样。

如果你有一条非短消息(任何包含LONG字对UI不好的话),操作将阻止队列中提交的其他重复任务的执行,大多数情况下经常证明没有更新(对于任务执行是如果是执行时间超过8毫秒的可运行的突发问题,那么在UI上完全或不确定。