Kotlin Coroutine Builders

Coroutine builders are functions that start a coroutine. Each builder has different behavior for how it runs, what it returns, and whether it blocks the calling thread. The three main builders are runBlocking, launch, and async.

runBlocking — Bridges Blocking and Coroutine Worlds

import kotlinx.coroutines.*

fun main() = runBlocking {
    println("Inside runBlocking")
    delay(500)
    println("Done after 500ms")
}
// runBlocking BLOCKS the main thread until all coroutines inside complete
// Use only for main() functions and tests — not in production coroutine code

launch — Fire and Forget

fun main() = runBlocking {
    val job = launch {
        delay(1000)
        println("launch coroutine done")
    }

    println("launch started — returns a Job, not a value")
    job.join()   // waits for this specific coroutine to finish
    println("All done")
}

Output:

launch started — returns a Job, not a value
launch coroutine done
All done

async — Returns a Result

fun main() = runBlocking {
    val deferred = async {
        delay(800)
        "Result from async"
    }

    println("async started — working in background...")
    val result = deferred.await()   // suspends here until result is ready
    println("Got: $result")
}

Output:

async started — working in background...
Got: Result from async

launch vs async Side by Side


                launch              async
────────────────────────────────────────────────────
Returns         Job                 Deferred
Get result?     NO                  YES via .await()
Use when?       side effects,       when you need the
                fire and forget     computed result

Parallel Execution with async

suspend fun loadUserName(): String { delay(600); return "Alice" }
suspend fun loadUserScore(): Int  { delay(400); return 1850     }

fun main() = runBlocking {
    val start = System.currentTimeMillis()

    // Sequential: ~1000ms total
    // val name  = loadUserName()
    // val score = loadUserScore()

    // Parallel: ~600ms total (both run at same time)
    val nameDeferred  = async { loadUserName() }
    val scoreDeferred = async { loadUserScore() }

    val name  = nameDeferred.await()
    val score = scoreDeferred.await()

    println("$name scored $score")
    println("Time: ${System.currentTimeMillis() - start}ms")
}

Output:

Alice scored 1850
Time: ~620ms

Multiple launch Jobs

fun main() = runBlocking {
    val jobs = List(5) { index ->
        launch {
            delay((index + 1) * 200L)
            println("Job $index complete")
        }
    }

    jobs.forEach { it.join() }   // wait for all
    println("All jobs finished")
}

Output:

Job 0 complete
Job 1 complete
Job 2 complete
Job 3 complete
Job 4 complete
All jobs finished

Cancelling a Job

fun main() = runBlocking {
    val job = launch {
        repeat(10) { i ->
            println("Working step $i")
            delay(300)
        }
    }

    delay(800)         // let it run for a bit
    job.cancel()       // cancel the coroutine
    job.join()         // wait for cancellation to complete
    println("Job cancelled")
}

Output:

Working step 0
Working step 1
Working step 2
Job cancelled

Practical Example: Dashboard Loader

suspend fun fetchStats(): String   { delay(500); return "Views: 1500, Sales: 320" }
suspend fun fetchAlerts(): String  { delay(300); return "2 low-stock alerts" }
suspend fun fetchRevenue(): String { delay(400); return "Revenue: ₹84,000" }

fun main() = runBlocking {
    val start = System.currentTimeMillis()

    val stats   = async { fetchStats()   }
    val alerts  = async { fetchAlerts()  }
    val revenue = async { fetchRevenue() }

    println("=== Dashboard ===")
    println(stats.await())
    println(alerts.await())
    println(revenue.await())
    println("Loaded in ${System.currentTimeMillis() - start}ms")
}

Output:

=== Dashboard ===
Views: 1500, Sales: 320
2 low-stock alerts
Revenue: ₹84,000
Loaded in ~520ms

Leave a Comment

Your email address will not be published. Required fields are marked *