用了快一年的kotlin了,一直对协程中的各种Dispatchers没有一个详细的了解。

本篇文章将讲解下面5种Dispatchers

  • Dispatchers.IO
  • Dispatchers.Unconfined
  • Dispatchers.Main
  • Dispatchers.Default
  • 在自建线程池中执行协程

Dispatchers.IO

internal object DefaultScheduler : ExperimentalCoroutineDispatcher() {
val IO: CoroutineDispatcher = LimitingDispatcher(
this,
systemProp(IO_PARALLELISM_PROPERTY_NAME, 64.coerceAtLeast(AVAILABLE_PROCESSORS)),
"Dispatchers.IO",
TASK_PROBABLY_BLOCKING
)

override fun close() {
throw UnsupportedOperationException("$DEFAULT_DISPATCHER_NAME cannot be closed")
}

override fun toString(): String = DEFAULT_DISPATCHER_NAME

@InternalCoroutinesApi
@Suppress("UNUSED")
public fun toDebugString(): String = super.toString()
}

IO本质上也是一个线程池,这是一个kotlin内部的共享线程池,线程池大小受到kotlinx.coroutines.io.parallelism文件的限制

1、如果kotlinx.coroutines.io.parallelism没有配置线程数量,则IO线程池的大小至少是64,如果你的核心数大于64,则IO的线程池数量为核心数。

2、如果kotlinx.coroutines.io.parallelism已经配置了线程数量,则IO线程池大小为kotlinx.coroutines.io.parallelism配置的线程数

如何修改默认的IO线程数量:

默认情况下,该配置是为空的。

image-20210121113006293

kotlinx.coroutines.io.parallelism本质上是JVM的一个系统配置参数,因此可以通过System.setProperty(IO_PARALLELISM_PROPERTY_NAME, Integer.toString(1000));修改线程数量

Dispatchers.Unconfined

非受限制调度器

第一个特性:

withContext(Dispatchers.Unconfined) {
println(1)
withContext(Dispatchers.Unconfined) { // Nested unconfined
println(2)
}
println(3)
}
println("Done")

输出:”1 2 3” 或 “1 3 2”,最终输出”Done”

如果在一个runBlocking周期内,切换的都是Dispatchers.Unconfined,那么后续代码的执行将是无序的。

第二个特性:

GlobalScope.launch {
println("Unconfined: I'm working in thread ${Thread.currentThread().name}")
withContext(Dispatchers.Main) { // Nested unconfined
println("Main: I'm working in thread ${Thread.currentThread().name}")
}
println("Unconfined: I'm working in thread ${Thread.currentThread().name}")
withContext(Dispatchers.IO) { // Nested unconfined
println("IO: I'm working in thread ${Thread.currentThread().name}")
}
println("Unconfined: I'm working in thread ${Thread.currentThread().name}")
}

输出:

Unconfined: I'm working in thread DefaultDispatcher-worker-1
Main: I'm working in thread main
Unconfined: I'm working in thread main
IO: I'm working in thread DefaultDispatcher-worker-1
Unconfined: I'm working in thread DefaultDispatcher-worker-1

使用了Dispatchers.Unconfined

GlobalScope.launch(Dispatchers.Unconfined) {
println("Unconfined: I'm working in thread ${Thread.currentThread().name}")
withContext(Dispatchers.Main) { // Nested unconfined
println("Main: I'm working in thread ${Thread.currentThread().name}")
}
println("Unconfined: I'm working in thread ${Thread.currentThread().name}")
withContext(Dispatchers.IO) { // Nested unconfined
println("IO: I'm working in thread ${Thread.currentThread().name}")
}
println("Unconfined: I'm working in thread ${Thread.currentThread().name}")
}

输出:

Unconfined: I'm working in thread main
Main: I'm working in thread main
Unconfined: I'm working in thread main
IO: I'm working in thread DefaultDispatcher-worker-2
Unconfined: I'm working in thread DefaultDispatcher-worker-2

1、在一个runBlocking区间内,切换线程后,后续的代码依然会在该线程中执行,直到下一次切换线程

2、在一个rubBlocking区间内,如果没有切换线程,代码则在launch所在的线程中执行,直到下一次切换线程

Dispatchers.Main

任务将在主线程中执行

Dispatchers.Default

默认的线程池,也就是Dispatchers.IO

在自建线程池中执行协程

GlobalScope.launch(Executors.newSingleThreadExecutor().asCoroutineDispatcher()){
// 将在线程池中执行
}