Kotlin中线程(Thread)与协程(Coroutine)的核心差异是什么?
Kotlin线程与协程的核心区别
1. 资源开销天差地别
- 线程是操作系统级别的实体,每个线程需要分配独立的栈空间(通常几MB),创建、切换、销毁都要操作系统内核参与,开销极大。
- 协程是用户态的轻量级“任务”,栈空间可以动态调整(通常几KB),所有操作都在用户态完成,创建上千个协程的开销可能都比不上一个线程。
2. 调度主体完全不同
- 线程由操作系统内核调度,调度策略是抢占式的——内核会强制中断正在运行的线程,切换到其他线程,开发者没法直接控制。
- 协程由Kotlin的协程框架(比如
kotlinx-coroutines)调度,是协作式的——只有当协程主动调用delay()、yield()这类挂起函数时,才会让出执行权,开发者能更精准地控制调度时机。
3. 阻塞与挂起的本质差异
- 线程阻塞时,整个线程会被操作系统挂起,占用的CPU资源会被收回,直到阻塞条件解除,这期间线程完全无法做任何事。
- 协程挂起时,只是把当前协程的执行状态保存起来,然后让出线程给其他协程使用;当挂起条件满足后,协程会在合适的线程上恢复执行,整个过程线程不会被阻塞,资源利用率更高。
代码示例对比
线程阻塞示例
fun threadDemo() { Thread { println("线程开始执行") Thread.sleep(1000) // 线程阻塞,这段时间该线程无法执行任何逻辑 println("线程执行结束") }.start() }
协程挂起示例
import kotlinx.coroutines.* fun coroutineDemo() = runBlocking { launch { println("协程开始执行") delay(1000) // 协程挂起,当前线程可去执行其他任务 println("协程执行结束") } println("主线程继续处理其他逻辑") }
4. 上下文切换成本
- 线程切换需要内核保存当前线程的寄存器、栈指针等状态,再加载另一个线程的状态,涉及内核态与用户态的切换,耗时较长。
- 协程切换仅需在用户态保存协程的局部变量、执行位置等信息,无需内核参与,切换成本几乎可以忽略。
5. 使用场景侧重点
- 线程更适合CPU密集型任务(比如大量数值计算),这类任务需要持续占用CPU,协程的协作式调度优势难以发挥。
- 协程更适合IO密集型任务(比如网络请求、数据库操作),这类任务大部分时间在等待IO完成,协程挂起时可让线程处理其他任务,大幅提升资源利用率。
内容的提问来源于stack exchange,提问作者Waseem Sajad
相关产品推荐
相关产品推荐

