This is another concept we discussed briefly in Chapter 8, Threads and Coroutines, in the Starting a coroutine section.
Remember how our launch() or async() could receive CommonPool?
Here's an example to remind you that you could specify it explicitly:
// Same as launch {}
launch(CommonPool) {
...
}
// Same as async {}
val result = async(CommonPool) {
...
}
This CommonPool is a Scheduler design pattern in a bad disguise. Many async tasks may be mapped to the same Scheduler.
Run the following code:
val r1 = async(CommonPool) {
for (i in 1..1000) {
println(Thread.currentThread().name)
yield()
}
}
r1.await()
What is interesting is the fact that the same coroutine is picked up by different threads:
ForkJoinPool.commonPool-worker-2
ForkJoinPool.commonPool-worker-3
...
ForkJoinPool.commonPool-worker-3
ForkJoinPool.commonPool-worker-1
You can also specify the context as Unconfined:
val r1 = async(Unconfined) {
...
}
This will run the coroutine on the main thread. It prints:
main
main
...
You can also inherit context from your parent coroutine:
val r1 = async {
for (i in 1..1000) {
val parentThread = Thread.currentThread().name
launch(coroutineContext) {
println(Thread.currentThread().name == parentThread)
}
yield()
}
}
Note though, that running in the same context doesn't mean that we run on the same thread.
You may ask yourself: what's the difference between inheriting the context and using Unconfined? We'll discuss this in detail in the next section.