2
votes

I'm trying to understand runBlocking in kotlin.

 println("before runBlocking ${Thread.currentThread().name}")

    runBlocking { // but this expression blocks the main thread
        delay(2000L) // non blocking
        println("inside runBlocking ${Thread.currentThread().name}")
        delay(2000L)
    }

    println("after runBlocking ${Thread.currentThread().name}")

Output

before runBlocking main
inside runBlocking main
after runBlocking main

Kotlin Says

  1. runBlocking - Runs a new coroutine and blocks the current thread interruptibly until its completion
  2. The main thread invoking runBlocking blocks until the coroutine inside runBlocking completes.

point 1 :- if runBlocking blocked the main thread in above example. Then inside runBlocking how i get the main thread again.

point 2 :- if Runs a new coroutine is true in above statement, then why it didn't create new coroutine inside runBlocking.

1
Bro, coroutine is not a thread. 2. Fetch the coroutine name inside by coroutineContext[CoroutineName], 1. runBlocking runs on parent thread(in here main) by blocking it, if no context is provided as parameter.Animesh Sahu

1 Answers

5
votes

The signature of runBlocking (doc) is

fun <T> runBlocking(
    context: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> T
): T (source)

If you see the context param, it has a default of an EmptyCoroutineContext. Hence when you don't pass a specific context, the default value is an event loop on the current thread. Since the current thread before running the runBlocking block was the main thread, whatever you ran inside the block is still on the main thread.

If you pass a coroutine context as below, you would have the block inside runBlocking running in a different thread.

println("before runBlocking ${Thread.currentThread().name}")

runBlocking(Dispatchers.Default) {
    delay(2000L)
    println("inside runBlocking ${Thread.currentThread().name}")
    delay(2000L)
}

println("after runBlocking ${Thread.currentThread().name}")

Output

before runBlocking main
inside runBlocking DefaultDispatcher-worker-1
after runBlocking main

Or if you launch runBlocking without passing the context, but launch a coroutine inside as below, you would see it running on the different thread.

println("before runBlocking ${Thread.currentThread().name}")

runBlocking { 
    println("inside runBlocking ${Thread.currentThread().name}")
    delay(2000L) 
    CoroutineScope(Dispatchers.Default).launch {
        println("inside runBlocking coroutineScope ${Thread.currentThread().name}")
    }
    delay(2000L)
}

println("after runBlocking ${Thread.currentThread().name}")

Output

before runBlocking main
inside runBlocking main
inside runBlocking coroutineScope DefaultDispatcher-worker-1
after runBlocking main