Chapo144
Chapo144

Reputation: 102

Can the coroutine launched through runBlocking be executed on 2 or more threads?

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

Answers (3)

k314159
k314159

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

Chapo144
Chapo144

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

Jan Itor
Jan Itor

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

Related Questions