android - 协程 - 带有连接的 Dispatchers.Main.immediate 在 runBlocking 内死锁

标签 android kotlin kotlin-coroutines

分解一个在Android上挂起主线程并与协程进行并发处理的简单案例,下面的代码只打印LaunchedrunBlocking永远不会完成:

runBlocking {
      val ioJob = launch(Dispatchers.IO) {
        delay(1000)
      }
      val mainJob = launch(Dispatchers.Main.immediate) {
        Log.d("Routine", "Launched")
        ioJob.join()
        Log.d("Routine", "Joined")
      }

      listOf(mainJob, ioJob).joinAll()
    }
当然,如果我们替换 Dispatchers.Main.immediateDispatchers.IO一切都很好,但是我的一些并发处理应该在 main 上运行。使用 Dispatchers.Main正如预期的那样,不记录任何内容。似乎曾经 joinrunBlocking 的根目录中执行它使发送到 main 的任何挂起的东西都瘫痪。
值得注意的是,基于 CountDownLatch 的方法和线程工作得很好:
    val latchMain = CountDownLatch(1)
    val primaryLatch = CountDownLatch(2)

    val ioExecutor = Executors.newCachedThreadPool(Executors.defaultThreadFactory())

    log("Execute IO")
    ioExecutor.execute(
        Runnable {
          log("Delay IO")
          Thread.sleep(1000)
          log("Countdown Main")
          latchMain.countDown()
          Thread.sleep(3000)
          primaryLatch.countDown()
        })

    log("Execute Main")
    Runnable {
      log("Await Main")
      latchMain.await()
      log("Countdown Primary")
      primaryLatch.countDown()
    }.run()

    log("Await Primary")
    primaryLatch.await()
    log("Continue")

    stepTracker.endTracking()
    return stepTracker.stepGraphTrace
  }

  private fun log(msg: String) = Log.i("Routine", "[${Thread.currentThread().name}] $msg")
带输出:
2021-08-11 11:04:06.508 [main] Execute IO
2021-08-11 11:04:06.509 [main] Execute Main
2021-08-11 11:04:06.510 [main] Await Main
2021-08-11 11:04:06.510 [pool-25-thread-1] Delay IO
2021-08-11 11:04:07.512 [pool-25-thread-1] Countdown Main
2021-08-11 11:04:07.513 [main] Countdown Primary
2021-08-11 11:04:07.513 [main] Await Primary
2021-08-11 11:04:10.514 [main] Continue
有任何想法吗?即将就这个问题向 JetBrains 提交问题。

最佳答案

假设 runBlocking代码是从主线程调用的,那么在 Dispatchers.Main 上启动的内部协程将永远不会到达主线程 Looper 上的队列前面,因为 runBlocking仍然阻塞主线程,所以协程永远无法启动。
当您使用 Main.immediate ,启动的协程的开头至少可以运行因为immediate如果您已经在主线程上,则将协程运行到第一个暂停点,如果您启动了 runBlocking在主线程上。当它到达挂起函数调用join() ,它被放入主线程looper的队列中,你又回到了与上面相同的问题。挂起函数调用总是打断协程的延续。

关于android - 协程 - 带有连接的 Dispatchers.Main.immediate 在 runBlocking 内死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68734377/

相关文章:

kotlin - 如何使用 kotlinx-coroutines-reactive 处理空场景?

android - 使用协程流时房间卡住->收集

android - USB设备识别为存储设备并查找路径

android - 我如何从自定义 View 中知道父填充?

android - 如何在 BaseFragment() 中传递 fragment 布局

android - Kotlin 协程列表返回空值

android - 如何在 Kotlin 协程中使用 Sqldelight

c# - Xamarin 从 2.5 更新到 3.5 后,Xamarin.Forms.Platform.Android 不存在

android - 如何从免费升级到商业而不丢失用户数据

android - 使用 Kotlin 将多个 OnClickListener 添加到 RecyclerView