runBlocking启动的协程能否多线程执行?是否保证线程一致?
关于runBlocking协程恢复线程的问题
结论:不一定会在启动时的t1线程恢复,完全有可能切换到Dispatcher.Default线程池里的其他线程(比如你猜测的DefaultDispatcher-worker-2)。
具体原因:
- 当你使用
runBlocking(Dispatchers.Default)时,协程运行在Default调度器的线程池上,这个线程池的默认线程数和CPU核心数一致(比如4核设备就是4个线程)。 delay()是一个非阻塞的挂起函数,它会让当前协程释放占用的线程(t1),这个线程会回到线程池供其他任务复用。- 当delay结束后,协程需要恢复执行,此时会从Default线程池里选取空闲的线程继续执行后续代码,这个线程可能是原来的t1,也可能是线程池里的其他线程。
为什么你每次都得到同一个线程?
这只是巧合——你的代码逻辑简单,没有其他并发任务抢占线程池资源。当delay结束时,原来的t1线程刚好处于空闲状态,所以协程直接复用了它。如果在delay期间,线程池里的其他线程被其他任务占用,恢复时就很可能切换到其他线程。
验证线程切换的方法
你可以在delay期间添加一些并发任务,占用线程池的其他线程,就能看到线程切换的现象:
fun main(): Unit = runBlocking(Dispatchers.Default) { println("runBlocking start: ${Thread.currentThread().name}") // 启动多个协程占用线程池资源 repeat(4) { launch { delay(2000) println("Child coroutine on: ${Thread.currentThread().name}") } } delay(3000) println("runBlocking end: ${Thread.currentThread().name}") }
运行这段代码,大概率会看到end的线程和start的线程不一样。
内容的提问来源于stack exchange,提问作者Chapo144
相关产品推荐
相关产品推荐

