为何在主线程调用runBlocking(Dispatchers.Main)总会死锁?
关于runBlocking在主线程中指定Dispatchers.Main导致阻塞的疑问
根据官方文档定义,runBlocking 的作用是:
Runs a new coroutine and blocks the current thread until its completion.
(翻译:启动一个新协程,并阻塞当前线程直到协程完成。)
我发现新协程仍可在当前线程中调度,但为何当当前线程为MAIN(即Dispatchers.Main)时,调用runBlocking(Dispatchers.Main)总会出现阻塞?
测试代码
无阻塞的情况
@Test fun runInMainThreadButNotBlocked() { val handler = Handler(Looper.getMainLooper()) handler.post { val mainTid = Thread.currentThread() Log.d("test", "main thread id is $mainTid") runBlocking { val tid = Thread.currentThread() Log.d("test", "runBlocking enter, tid is $tid") // 打印主线程 Log.d("test", "runBlocking leave") } } }
始终阻塞的情况
@Test fun runInMainThreadAlwaysBlocked() { val handler = Handler(Looper.getMainLooper()) handler.post { val mainTid = Thread.currentThread() Log.d("test", "main thread id is $mainTid") runBlocking(Dispatchers.Main) { // 永远无法进入 val tid = Thread.currentThread() Log.d("test", "runBlocking enter, tid is $tid") // 仍会打印主线程(如果能执行的话) Log.d("test", "runBlocking leave") } } }
原因解释
runBlocking的默认调度逻辑
当不指定Dispatcher调用runBlocking时,它会使用当前线程专属的BlockingEventLoop作为调度器。对于主线程来说,这个EventLoop不需要依赖主线程的Looper消息队列,而是直接在当前线程上同步执行协程体,所以不会出现阻塞,协程代码能正常运行。指定Dispatchers.Main时的死锁逻辑
当显式传入Dispatchers.Main时,runBlocking会把协程任务提交到主线程的Looper消息队列中等待执行。但runBlocking本身会阻塞当前主线程,直到协程完成——而主线程被阻塞后,根本无法处理Looper消息队列里的协程任务,协程永远得不到执行,runBlocking也就永远不会结束,形成了死锁。
这就是第二个测试中协程体永远无法进入、程序一直阻塞的核心原因。
内容的提问来源于stack exchange,提问作者progquester
相关产品推荐
相关产品推荐

