java - Android:将另一个线程的可运行文件发布到主线程实际上有什么作用?

标签 java android multithreading

所以,正如标题所说:当您将另一个线程的可运行文件发布到主线程时,实际上会发生什么?

我看到很多问题询问你是如何做到的,以及它的基本原理是如何工作的。但是,当您在 MessageQueue 上放置一个 runnable 时,我很难找到一个确切的解释。轮到 Runnable 时它会运行,当然。但这是什么时候?

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

我问的主要原因是这样我可以更好地了解我需要牢记哪些注意事项以防止由于多线程导致的错误。 (特别是旧请求影响已刷新页面的情况)

最佳答案

首先,你需要了解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] 字段都将被忽略。如果 callbackMessage 为空由 [SWITCHED] 字段定义并在 Handler's 中处理。覆盖 handleMessage()handleMessage()Handler.Callback处理程序被初始化。
MessageQueuewhen 排序 field 。 Looper直到当前时间(由 SystemClock.uptimeMillis 测量)才会出列并处理消息, 大于或等于消息的 when 中存储的时间 field 。

当您调用 Handler#post(Runnable r)发生以下事情:
  • 一个 Message从池中获取(一个简单的静态链表
    Message类)
  • 您的 Runnable分配给消息的 callback field 。
  • when如果没有延迟或特定,则字段仅设置为当前时间
    时间已过
  • Message排入MessageQueue .如果 when
    早于队列的头部,它成为一个新的头部。如果
    不是,而是插入到中间,以便 MessageQueue仍按 when 排序
  • Looper这是一个非终止循环,使消息出队
    从队列中按顺序处理它们(无交织),
    最终,将我们的消息出列并调用 dispatchMessage()
    最初发布 Runnable 的处理程序.
  • 处理程序决定消息是 [RUNNABLE] 还是
    [SWITCHED] 并相应地处理它。特别是它调用run()callback如果存在

  • 这应该可以回答您关于 Runnable 行为的问题。在阻塞任务期间发布在 UI 线程上 - 嗯,不,它不会中断正在进行的任务,也不会交织 .线程上发生的所有事情首先进入MessageQueue。 , 按钮点击或您的自定义 Runnables您从其他线程发布的。基本上不可能以其他方式发生:Looper.loop()只是让线程忙于它的for(;;)环形。

    不过,有一些方法可以更改消息的顺序。

    例如,在 Looper/Handler 框架中有一个有趣的同步屏障概念。按照惯例,同步屏障只是 Message为空 target (所以它基本上只是一个类似标志的东西,没有处理程序来调度它)。如果它与 postSyncBarrier() 一起放入队列中,出列的整个过程发生变化,直到同步屏障从队列中移除 removeSyncBarrier() . Messages未标记为 isAsynchronous将被忽略,根本不会出队和处理。相反,将扫描队列,直到出现 isAsynchronous = true 的消息。被发现。然后将根据其when 进行调度。并在时机成熟时进行处理。

    此外,您可以调用不言自明的 Handler#postAtFrontOfQueue() , 但是,正如文档中指出的那样

    This method is only for use in very special circumstances -- it can easily starve the message queue, cause ordering problems, or have other unexpected side-effects.



    建议您浏览source code所有提到的类。它读起来就像一本很好的小说书。

    关于java - Android:将另一个线程的可运行文件发布到主线程实际上有什么作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34124845/

    相关文章:

    java - 套接字 () - 错误 : variable client might not have been initialized

    java - 向现有方法添加异常

    android - 有没有办法检测通知栏是否已被清除?

    android:从另一个类中的另一个线程更新用户界面

    c - 如何在openmp中为每个线程分配特定的作业以进行矩阵加法

    java - 如何转换为指定的类类型?

    java - 将迭代器设置为字符串 - JAVA

    android - 如何从 Android 中的视频文件路径创建视频缩略图?

    android - 对 ViewPager 的 PagerAdapter 有误解。 InstantianteItem 方法永远不会被调用

    C++11:如果不为 std::thread 调用 join() 会发生什么