In this short article, I will explain how to use runBlocking
with multiple threads. Let's analyze the code below. This is a quite popular use case of coroutines utilization. We can imagine that we make two different calls to two different services asynchronously and return the combined response.
fun main() {
val response =
runBlocking {
val responseA = async { callToServiceA() }
val responseB = async { callToServiceB() }
return@runBlocking "${responseA.await()} + ${responseB.await()}"
}
println(response)
}
suspend fun callToServiceA(): Int {
println("Start -> Service A thread: ${Thread.currentThread().id}")
delay(1000)
println("End -> Service A thread: ${Thread.currentThread().id}")
return Random(1).nextInt()
}
suspend fun callToServiceB(): Int {
println("Start -> Service B thread: ${Thread.currentThread().id}")
delay(1000)
println("End -> Service B thread: ${Thread.currentThread().id}")
return Random(1).nextInt()
}
That's how the results look like:
Start -> Service A thread: 1
Start -> Service B thread: 1
End -> Service A thread: 1
End -> Service B thread: 1
600123930 + 600123930
So we can easily notice that both asynchronous tasks use the same thread. Even though async
block uses Default
coroutine dispatcher, because context is inherited from the outer scope (in this case from runBlocking
). If we don't specify any CoroutineDispatcher
, then all coroutines will be running on the current thread.
How can we execute async
in a different thread?
The solution will be very easy. We can change the context
of runBlocking
to context = Dispatchers.Default
. Then the output of the above code snippet will be:
Start -> Service A thread: 14
Start -> Service B thread: 15
End -> Service A thread: 14
End -> Service B thread: 15
600123930 + 600123930
Finally, our async
blocks run concurrently.