Dispatcher 应该是我们使用 withContext 最常使用的参数了,我们可以用 withContext 来改变后面 lambda block 中的执行线程,可以对比一下 work1 和work2 的执行线程。没错,确实改变了!!!那 log 里为什么 work1 和 do work2用的是同一个线程呢?因为 Dispatchers.IO 和 Dispatchers.Default 会共用缓存的线程池,后面讲协程里的线程池时会详细展开。当 DefaultDispatcher-worker-1 线程执行完 work1 之后线程就空闲出来了,使用 Dispatchers.IO 的时候便复用了这个线程,所以看起来是一样的。那为什么后面打印 work2 又在 DefaultDispatcher-worker-3 线程呢?因为线程的任务执行本身是相互竞争的,withContext 会启动一个新的协程,这个协程可能会被其他线程获取到。如果你执行多次的话会发现每次打印的线程都可能会变化,自己动手试试。
fun main() {
val coroutineScope = CoroutineScope(Dispatchers.Default)
coroutineScope.launch {
// 1. context[ContinuationInterceptor] = Dispatchers.Default
printlnWithThread("work1")
val work2 = withContext(Dispatchers.IO) {
// 2. context[ContinuationInterceptor] = Dispatchers.IO
printlnWithThread("do work2 ...")
"work2"
}
// 3. // context[ContinuationInterceptor] = Dispatchers.Default
printlnWithThread(work2)
}
Thread.sleep(100)
}
运行结果如下
DefaultDispatcher-worker-1: work1 DefaultDispatcher-worker-1: do work2 ... DefaultDispatcher-worker-3: work2 |