协程与线程数:Thread.sleep()与delay()差异及额外线程探究
协程Dispatcher线程数疑问解析
我用线程池大小为1的自定义Dispatcher测试协程,代码如下:
const val customThreadPoolSize = 1 val customDispatcher = Executors.newFixedThreadPool(customThreadPoolSize).asCoroutineDispatcher()
我写了两个函数,各包含5个模拟工作的协程:
- 在fun1中,用
Thread.sleep()模拟耗时操作 - 在fun2中,用
delay()模拟耗时操作
fun1 代码
fun fun1() { println("Current thread is: ${Thread.currentThread().name}") println("Current number of threads is: ${Thread.activeCount()}") GlobalScope.launch(customDispatcher) { println("(Coroutine1) Current thread is: ${Thread.currentThread().name}") println("(Coroutine1) Current number of threads is: ${Thread.activeCount()}") for (i in 0..3) { println("(Coroutine1) Doing work:$i") Thread.sleep(1000) // 在工作线程执行任务,会完全阻塞线程 } println("(Coroutine1) Coroutine1 finished work") } GlobalScope.launch(customDispatcher) { println("(Coroutine2) Current thread is: ${Thread.currentThread().name}") println("(Coroutine2) Current number of threads is: ${Thread.activeCount()}") for (i in 0..3) { println("(Coroutine2) Doing work:$i") Thread.sleep(1000) // 在工作线程执行任务,会完全阻塞线程 } println("(Coroutine2) Coroutine2 finished work") } GlobalScope.launch(customDispatcher) { println("(Coroutine3) Current thread is: ${Thread.currentThread().name}") println("(Coroutine3) Current number of threads is: ${Thread.activeCount()}") for (i in 0..3) { println("(Coroutine3) Doing work:$i") Thread.sleep(1000) // 在工作线程执行任务,会完全阻塞线程 } println("(Coroutine3) Coroutine3 finished work") } GlobalScope.launch(customDispatcher) { println("(Coroutine4) Current thread is: ${Thread.currentThread().name}") println("(Coroutine4) Current number of threads is: ${Thread.activeCount()}") for (i in 0..3) { println("(Coroutine4) Doing work:$i") Thread.sleep(1000) // 在工作线程执行任务,会完全阻塞线程 } println("(Coroutine4) Coroutine4 finished work") } println("Current thread is: ${Thread.currentThread().name}") println("Current number of threads is: ${Thread.activeCount()}") GlobalScope.launch(customDispatcher) { println("(Coroutine5) Current thread is: ${Thread.currentThread().name}") println("(Coroutine5) Current number of threads is: ${Thread.activeCount()}") for (i in 0..3) { println("(Coroutine5) Doing work:$i") Thread.sleep(1000) // 在工作线程执行任务,会完全阻塞线程 } println("(Coroutine5) Coroutine5 finished work") } println("Current thread is: ${Thread.currentThread().name}") println("Current number of threads is: ${Thread.activeCount()}") for (i in 0..3) { println("(Main thread) Doing work:$i") Thread.sleep(1000) // 在主线程执行任务 } println("(Main thread) Main thread finished work") customDispatcher.close() }
fun1 运行输出
Current thread is: main Current number of threads is: 2 Current thread is: main Current number of threads is: 3 Current thread is: main Current number of threads is: 3 (Main thread) Doing work:0 (Coroutine1) Current thread is: pool-1-thread-1 (Coroutine1) Current number of threads is: 3 (Coroutine1) Doing work:0 (Main thread) Doing work:1 (Coroutine1) Doing work:1 (Coroutine1) Doing work:2 (Main thread) Doing work:2 (Coroutine1) Doing work:3 (Main thread) Doing work:3 (Coroutine1) Coroutine1 finished work (Main thread) Main thread finished work (Coroutine2) Current thread is: pool-1-thread-1 (Coroutine2) Current number of threads is: 3 (Coroutine2) Doing work:0 (Coroutine2) Doing work:1 (Coroutine2) Doing work:2 (Coroutine2) Doing work:3 (Coroutine2) Coroutine2 finished work (Coroutine3) Current thread is: pool-1-thread-1 (Coroutine3) Current number of threads is: 3 (Coroutine3) Doing work:0 (Coroutine3) Doing work:1 (Coroutine3) Doing work:2 (Coroutine3) Doing work:3 (Coroutine3) Coroutine3 finished work (Coroutine4) Current thread is: pool-1-thread-1 (Coroutine4) Current number of threads is: 3 (Coroutine4) Doing work:0 (Coroutine4) Doing work:1 (Coroutine4) Doing work:2 (Coroutine4) Doing work:3 (Coroutine4) Coroutine4 finished work (Coroutine5) Current thread is: pool-1-thread-1 (Coroutine5) Current number of threads is: 3 (Coroutine5) Doing work:0 (Coroutine5) Doing work:1 (Coroutine5) Doing work:2 (Coroutine5) Doing work:3 (Coroutine5) Coroutine5 finished work
如上所示,最大工作线程数为3。
fun2 运行输出
Current thread is: main Current number of threads is: 2 Current thread is: main Current number of threads is: 3 Current thread is: main Current number of threads is: 3 (Main thread) Doing work:0 (Coroutine1) Current thread is: pool-1-thread-1 (Coroutine1) Current number of threads is: 3 (Coroutine1) Doing work:0 (Coroutine2) Current thread is: pool-1-thread-1 (Coroutine2) Current number of threads is: 4 (Coroutine2) Doing work:0 (Coroutine3) Current thread is: pool-1-thread-1 (Coroutine3) Current number of threads is: 4 (Coroutine3) Doing work:0 (Coroutine4) Current thread is: pool-1-thread-1 (Coroutine4) Current number of threads is: 4 (Coroutine4) Doing work:0 (Coroutine5) Current thread is: pool-1-thread-1 (Coroutine5) Current number of threads is: 4 (Coroutine5) Doing work:0 (Main thread) Doing work:1 (Coroutine1) Doing work:1 (Coroutine2) Doing work:1 (Coroutine3) Doing work:1 (Coroutine4) Doing work:1 (Coroutine5) Doing work:1 (Main thread) Doing work:2 (Coroutine1) Doing work:2 (Coroutine2) Doing work:2 (Coroutine3) Doing work:2 (Coroutine4) Doing work:2 (Coroutine5) Doing work:2 (Main thread) Doing work:3 (Coroutine1) Doing work:3 (Coroutine2) Doing work:3 (Coroutine3) Doing work:3 (Coroutine4) Doing work:3 (Coroutine5) Doing work:3
此时,最大工作线程数为4。
疑问
请问这个额外的线程来自哪里,它的作用是什么?
解答
这个额外的线程是Kotlin协程框架自带的DefaultExecutor线程,专门负责处理协程挂起后的恢复任务。
当你用delay()时,协程会被挂起,delay本质是个定时任务——到点后得把挂起的协程唤醒,让它继续执行。这个唤醒操作就需要DefaultExecutor的线程来触发,它是个单线程池,专门处理这类协程回调、挂起恢复的活儿。
反观fun1里用Thread.sleep(),这是实打实的阻塞线程,协程根本不会挂起,所有任务都在自定义的单线程池里排队串行跑,不需要唤醒操作,自然也不会用到DefaultExecutor,所以线程数不会多出来。
另外提一句:Thread.activeCount()统计的是当前JVM里所有活跃线程,包括主线程、自定义线程池的线程,还有JVM自带的一些守护线程(比如Finalizer线程)。fun1里的3个线程就是主线程+自定义线程+1个守护线程;fun2里多的那个就是DefaultExecutor的线程。
内容的提问来源于stack exchange,提问作者Mena
相关产品推荐
相关产品推荐

