首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Coroutines带有联接的Dispatchers.Main.immediate在runBlocking中死锁

Coroutines带有联接的Dispatchers.Main.immediate在runBlocking中死锁
EN

Stack Overflow用户
提问于 2021-08-10 23:16:26
回答 3查看 1.6K关注 0票数 4

在Android上分解一个简单的案例来挂起主线程并使用协同执行并发处理,下面的代码只打印LaunchedrunBlocking从未完成:

代码语言:javascript
运行
复制
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.immediate代替Dispatchers.IO,一切都会很好,但是我的一些并发处理应该在main上运行。使用Dispatchers.Main不会像预期的那样记录任何内容。看来,一旦在join根目录下执行了一个runBlocking,它就会瘫痪所有被分派到main的挂起的东西。

值得注意的是,一种基于CountDownLatch和线程的方法非常有效:

代码语言:javascript
运行
复制
    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")

产出:

代码语言:javascript
运行
复制
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提交一个问题。

EN

Stack Overflow用户

回答已采纳

发布于 2021-08-11 06:16:20

注意:要清除问题,不应该故意用runBlocking阻止主/ UI线程,因为当UI线程在runBlocking中释放(如果它挂起)的子协同时,runBlocking之外的任何东西都不会被执行(没有绘制方法,也没有),这会导致在runBlocking处于活动状态的情况下冻结UI。

这可能是因为"immediate“是如何实现的。它不仅仅是join(),它是任何挂起函数,如果您调用yield(),它不会有帮助,如果您调用delay() mainJob,则只在延迟完成时才会恢复。基本上,只要mainJob正在运行,runBlocking就不会恢复,而runBlockingmainJob完成之前不会完成,这是一个定义为死锁

您可以省略将Dispatcher.Main.immediate指定给mainJob,让它从runBlocking继承它的上下文。如果您想在mainJob声明后立即开始执行它,只需将线程从runBlocking输出到它。

代码语言:javascript
运行
复制
runBlocking {
    log("runBlocking: start")

    val ioJob = launch(Dispatchers.IO) {
        log("ioJob: About to delay")
        delay(1000)
        log("ioJob: Delay done")
    }

    val mainJob = launch {
        log("mainJob: About to join ioJob")
        ioJob.join()
        log("mainJob: ioJob successfully joined")
    }


    // yield() if you want to start executing mainJob before the rest of the runBlocking code

    log("runBlocking: about to join jobs")
    listOf(ioJob, mainJob).joinAll()
    log("runBlocking: jobs joined, exiting")
}

private fun log(msg: String) = Log.i("MainActivity", "[${Thread.currentThread().name}] $msg")

w/o产量()

代码语言:javascript
运行
复制
I/MainActivity: [main] runBlocking: start
I/MainActivity: [main] runBlocking: about to join jobs
I/MainActivity: [DefaultDispatcher-worker-1] ioJob: About to delay
I/MainActivity: [main] mainJob: About to join ioJob
I/MainActivity: [DefaultDispatcher-worker-3] ioJob: Delay done
I/MainActivity: [main] mainJob: ioJob successfully joined
I/MainActivity: [main] runBlocking: jobs joined, exiting

票数 2
EN
查看全部 3 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68734377

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档