在Android上分解一个简单的案例来挂起主线程并使用协同执行并发处理,下面的代码只打印Launched
和runBlocking
从未完成:
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
和线程的方法非常有效:
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提交一个问题。
发布于 2021-08-11 06:16:20
注意:要清除问题,不应该故意用runBlocking
阻止主/ UI线程,因为当UI线程在runBlocking
中释放(如果它挂起)的子协同时,runBlocking
之外的任何东西都不会被执行(没有绘制方法,也没有),这会导致在runBlocking处于活动状态的情况下冻结UI。
这可能是因为"immediate
“是如何实现的。它不仅仅是join()
,它是任何挂起函数,如果您调用yield()
,它不会有帮助,如果您调用delay()
mainJob
,则只在延迟完成时才会恢复。基本上,只要mainJob
正在运行,runBlocking
就不会恢复,而runBlocking
在mainJob
完成之前不会完成,这是一个定义为死锁。
您可以省略将Dispatcher.Main.immediate
指定给mainJob
,让它从runBlocking
继承它的上下文。如果您想在mainJob
声明后立即开始执行它,只需将线程从runBlocking
输出到它。
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产量()
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
https://stackoverflow.com/questions/68734377
复制相似问题