Kotlin Dispatchers
A dispatcher decides which threads a coroutine runs on. Code picks a dispatcher at launch or switches to one for a block with withContext.
withContext computes on Default
The sum runs inside withContext on Dispatchers.Default. The returned value reaches main, and main prints it.
import kotlinx.coroutines.*
fun main() = runBlocking {
val total = withContext(Dispatchers.Default) {
(1..100).sum()
}
println("total: $total")
}withContext returns before the next line
The block joins three letters and returns the joined text. The line after withContext runs only when that value is back.
import kotlinx.coroutines.*
fun main() = runBlocking {
val text = withContext(Dispatchers.Default) {
val words = listOf("a", "b", "c")
words.joinToString("-")
}
println(text)
println("back in main")
}launch takes a dispatcher
The dispatcher is the first argument of launch. join waits for the background work before the joined line prints.
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch(Dispatchers.Default) {
println("background work done")
}
job.join()
println("joined")
}An executor as a dispatcher
A single thread executor becomes a dispatcher, and two async blocks run on it. The awaits print in a fixed order, and close releases the dispatcher.
import kotlinx.coroutines.*
import java.util.concurrent.Executors
fun main() = runBlocking {
val single = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
val first = async(single) {
"first"
}
val second = async(single) {
"second"
}
println(first.await())
println(second.await())
single.close()
println("closed")
}Example
import kotlinx.coroutines.*
import java.util.concurrent.Executors
fun main() = runBlocking {
val total = withContext(Dispatchers.Default) {
(1..50).sum()
}
println(total)
val single = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
val first = async(single) {
"alpha"
}
val second = async(single) {
"beta"
}
println(first.await())
println(second.await())
single.close()
}Key points
- Dispatchers.Default is a shared dispatcher suited to work in the background.
- withContext runs its block on the given dispatcher.
- withContext returns the value of its block to the caller.
- launch and async accept a dispatcher as the first argument.
- An executor becomes a dispatcher with asCoroutineDispatcher.
- A dispatcher built from an executor is closed when the work is done.
In this example, withContext sends the sum of 1 to 50 to Dispatchers.Default and returns 1275. The executor dispatcher then runs two async blocks, and the awaits print alpha before beta. The close call at the end releases the executor dispatcher.
Note
This lesson states computed results only, never the name of a thread.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Kotlin Playground
Exercise
What does withContext(Dispatchers.Default) { (1..10).sum() } give back to the caller?