Reputation: 102
I have this runBlocking code and I wanted to know if its guaranteed that coroutine launched through runBlocking will always execute on the same thread (i.e. thread on which runBlocking started executing) ?
1st println will show say Thread t1. But after the suspend function delay is executed, I want to know will this coroutine resume in same Thread t1 or is it possible to be executed on different thread Thread t2 ? This is because a coroutine can be executed on 2 or more threads so the coroutine created by runBlocking can execute on thread t1 and get suspended on delay() and resume on different thread t2.
fun main(): Unit = runBlocking(Dispatchers.Default) { // Thread t1
println("runBlocking start: ${Thread.currentThread().name}") // Thread t1
delay(3000)
println("runBlocking end: ${Thread.currentThread().name}") // is it necessary to be t1 ?
}
The output I am getting every time is(but I feel that in 2nd line of output it could also have been DefaultDispatcher-worker-2):--
runBlocking start: DefaultDispatcher-worker-1
runBlocking end: DefaultDispatcher-worker-1
Upvotes: 1
Views: 79
Reputation: 11100
Unlike the answer by @jan-itor, you don't need to wrap the delay
call in async
. If you call runBlocking
in two separate threads, you can see the effect of the delay
call alone:
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
fun main() {
repeat(2) { rep ->
thread {
runBlocking(Dispatchers.Default) {
log("$rep: runBlocking start")
delay(50)
log("$rep: runBlocking end")
}
}
}
}
Output:
[DefaultDispatcher-worker-1] 1: runBlocking start
[DefaultDispatcher-worker-2] 0: runBlocking start
[DefaultDispatcher-worker-2] 1: runBlocking end
[DefaultDispatcher-worker-1] 0: runBlocking end
This shows that in the runBlocking
call of rep 1 started in thread DefaultDispatcher-worker-1
and finished in thread DefaultDispatcher-worker-2
, while in rep 0 it was the opposite.
You can see this more clearly if you run with the -Dkotlinx.coroutines.debug
VM option:
[DefaultDispatcher-worker-2 @coroutine#2] 1: runBlocking start
[DefaultDispatcher-worker-1 @coroutine#1] 0: runBlocking start
[DefaultDispatcher-worker-6 @coroutine#1] 0: runBlocking end
[DefaultDispatcher-worker-1 @coroutine#2] 1: runBlocking end
Upvotes: 1
Reputation: 102
@jan-itor answer is correct and solved my query.
Although using DefaultDispatcher is printing same thread every time for my PC.
I created my own custom CorotuineDispatcher to demonstrate that this coroutine might also get executed on 2 different threads.
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
fun main(): Unit = runBlocking(Executors.newFixedThreadPool(100).asCoroutineDispatcher()) {
log("runBlocking start") // [pool-1-thread-1] runBlocking start
async { delay(500) }.await()
log("runBlocking end") //[pool-1-thread-4] runBlocking end
}
Upvotes: 1
Reputation: 4216
Yes, as long as you specify a multi-threaded dispatcher like Dispatchers.Default
.
Try launching a new coroutine or two inside runBlocking
:
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
fun main(): Unit = runBlocking(Dispatchers.Default) {
log("runBlocking start")
async { delay(50) }.await()
log("runBlocking end")
}
Eventually, different threads will be printed:
[DefaultDispatcher-worker-1 @coroutine#1] runBlocking start
[DefaultDispatcher-worker-2 @coroutine#1] runBlocking end
Upvotes: 4