You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

协程与线程数: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:20:54