Skip to content

Unconfined:性能与行为

源:Unconfined 调度器参考

Dispatchers.Unconfined 是一种不做任何调度的调度器。

运行机制

它像一棵随风飘荡的草:

  1. 启动时:在调用者线程立即执行,直到第一个挂起点。
  2. 恢复时:在恢复仅仅发生所在的线程继续执行。
kotlin
withContext(Dispatchers.Unconfined) {
    println(Thread.currentThread().name) // 1. 在原线程执行
    
    delay(100) // 挂起... 假设 delay 由 DefaultExecutor 恢复
    
    println(Thread.currentThread().name) // 2. 这里的线程变成了 DefaultExecutor 线程!
}

致命风险:StackOverflow

Unconfined 最可怕的特性是:如果协程只是名义上挂起,但实际上立即恢复(例如 job.join() 但 job 已经完成),Unconfined 会在当前栈帧直接执行后续代码。

如果这种模式在循环中发生,调用栈会无限叠加,导致栈溢出。

kotlin
// 只有 Unconfined 会引发 StackOverflowError
// 每一个 yield 都应该切线程,但 Unconfined 不切,直接在栈上叠加
launch(Dispatchers.Unconfined) {
    while (true) {
        yield() 
    }
}

适用场景

生产环境慎用

99% 的业务代码不应该使用 Unconfined。

  1. 单元测试: runTest 内部使用了类似机制,为了让测试代码同步执行,消除并发不确定性。
  2. 微小的非阻塞任务: 如果你确实不想付出切换线程的开销,且非常清楚代码流程。
    • 例如:简单的日志埋点、内存计算。

与 Main.immediate 的区别

Main.immediate 也是“如果是当前线程则不调度”。

  • 区别Main.immediate 有目标(必须在 Main),如果当前不是 Main,它会调度到 Main。
  • Unconfined:没目标,爱在哪跑在哪跑。