Chapter 23: Coroutines – Basics (Kotlin’s #1 Superpower)

Coroutines – Basics (Kotlin’s #1 Superpower) — this is the chapter that makes Kotlin feel like a superhero language! ☕🚀

Coroutines are Kotlin’s way to handle concurrency (doing multiple things at once) in a simple, safe, and efficient manner. They’re like lightweight threads — but without the complexity, memory overhead, or blocking issues of traditional threads. In 2026, coroutines are everywhere — Android apps, backend servers (Ktor, Spring WebFlux), games, data processing… you name it!

If threads are like hiring a team of heavy-duty workers (expensive, hard to manage), coroutines are like super-efficient multitasking robots that can switch tasks instantly without wasting resources.

We’re going to cover:

  • Suspending functions (suspend)
  • runBlocking
  • launch
  • async / await
  • Coroutine builders & scopes

I’ll explain everything very slowly, like we’re sitting together in a quiet Bandra café — with real-life analogies, complete runnable examples (copy-paste into IntelliJ with Kotlin 1.9+), step-by-step breakdowns, tables, common mistakes with fixes, and fun facts so everything sticks perfectly.

Important setup:

  • Add this to your build.gradle.kts (or build.gradle):
    Kotlin
  • Or in IntelliJ: File → New → Project → Kotlin → Multiplatform → Add coroutines dependency.

Let’s start!

1. Suspending Functions (suspend) – The Foundation of Coroutines

A suspending function is a function that can pause its execution at certain points (suspension points) without blocking the thread — and resume later.

Key points:

  • Marked with suspend keyword
  • Can call other suspend functions (like delay())
  • Does not block the thread — frees it for other work
  • Can only be called from another suspend function or from a coroutine builder (like launch, async)

Real-life analogy: You’re cooking rice (long task).

  • Normal function → stand there waiting (block the kitchen)
  • Suspend function → set timer, go do other chores (free the kitchen), come back when done.

Example 1 – Basic suspend function

Kotlin

Output (after 2 seconds):

text

Step-by-step:

  1. suspend fun → marks it as suspendable
  2. delay(2000) → suspension point → pauses coroutine, not thread
  3. Cannot call from normal main() — must use a coroutine context (like runBlocking)

Fun fact: delay() is like Thread.sleep() but non-blocking — the thread is free to do other work!

2. runBlocking – Bridge Between Blocking & Non-Blocking Worlds

runBlocking is a coroutine builder that:

  • Blocks the current thread until all coroutines inside finish
  • Used to call suspend functions from non-suspend code (like main())

Use it for:

  • Main function in console apps
  • Unit tests
  • Bridge to legacy blocking code

Do NOT use in:

  • Android UI (blocks main thread → ANR)
  • Servers (blocks worker threads)

Example 2 – runBlocking with multiple suspend calls

Kotlin

Output (after 3 seconds total):

text

Step-by-step:

  1. runBlocking { … } → creates a blocking coroutine on current thread
  2. Inside the block → you can call suspend functions
  3. It waits (blocks) until everything inside finishes

3. launch – Fire-and-Forget Coroutines

launch is a coroutine builder that:

  • Launches a new coroutine concurrently
  • Returns a Job (handle to control/cancel it)
  • Does not return a result — use for side-effects (fire-and-forget)

Real-life analogy: You’re the boss — launch is like telling your assistant: “Go do this task in background — I’ll continue my work.”

Example 3 – launch concurrent coroutines

Kotlin

Output (after 2 seconds total):

text

Step-by-step:

  1. launch { … } → starts a new coroutine in parallel
  2. Returns Job → use join() to wait, cancel() to stop
  3. Inside runBlocking → main thread waits for joins

4. async / await – Coroutines with Results

async is like launch but:

  • Returns a Deferred<T> (promise/future with result)
  • Use await() to get the result (suspends until ready)

Real-life analogy: You ask your assistant: “Go buy groceries and bring back the receipt” (async) → you wait for the receipt (await) before paying bills.

Example 4 – async / await concurrent tasks

Kotlin

Output (after 2 seconds total — concurrent!):

text

Step-by-step:

  1. async { … } → starts concurrent coroutine, returns Deferred<T>
  2. await() → suspends until result ready → returns T
  3. Runs in parallel → total time is max of delays (2s, not 3.5s)

Common pattern – structured concurrency: All launch / async inside a scope → parent waits for children.

5. Coroutine Builders & Scopes – The Structure

Coroutine builders = functions that start coroutines (launch, async, runBlocking)

Coroutine scopes = contexts that manage lifecycle of coroutines (wait for children, cancel, handle exceptions).

Builder Returns Blocks? Purpose
runBlocking Lambda result Yes Bridge blocking code to coroutines
launch Job No Fire-and-forget side effects
async Deferred<T> No Compute value concurrently
coroutineScope Lambda result No (suspends) Structured scope inside suspend function

GlobalScope (avoid in 2026!):

  • GlobalScope.launch { … } → runs globally — not structured, can leak
  • Best practice: Always use structured scopes (coroutineScope, viewModelScope, etc.)

Example 5 – coroutineScope for structured concurrency

Kotlin

Output:

text

Step-by-step:

  1. coroutineScope { … } → creates a child scope
  2. All launches inside are children — scope waits for them
  3. If one child crashes → all siblings cancel + exception propagates

Quick Recap Table (Your Cheat Sheet)

Concept Key Points / Example Benefit
suspend suspend fun longTask() { delay(1000) } Non-blocking pause
runBlocking runBlocking { longTask() } Block thread for coroutines
launch launch { delay(1000) } → Job Concurrent side-effect
async async { delay(1000) } → Deferred<T> Concurrent value computation
await deferred.await() → T Get async result
coroutineScope coroutineScope { launch { … } } Structured concurrency – wait for children

Common Newbie Mistakes & Fixes

Mistake Problem Fix
Calling suspend from non-suspend Compile error Use runBlocking or another builder
Not using await on async Deferred<T> not resolved Always call .await()
Using GlobalScope Leaks, unstructured Use coroutineScope or structured scopes
Forgetting to import kotlinx.coroutines Cannot find delay, launch Add dependency & import kotlinx.coroutines.*
Blocking in UI coroutines UI freeze Use non-blocking suspend (delay, not Thread.sleep)

Homework for You (Let’s Make It Fun!)

  1. Basic Create a suspend function suspend fun helloDelay(name: String) → delay 1s → print “नमस्ते $name!”. Call from runBlocking.
  2. Medium Use launch to run 3 concurrent tasks that print after different delays.
  3. Advanced Use async to fetch two values concurrently → await both → print their sum.
  4. Fun Simulate a race: 2 coroutines “running” with delays → first to finish wins!
  5. Challenge Fix this code:
    Kotlin

You’ve just unlocked Kotlin’s #1 superpowercoroutines! Now you can write concurrent code that’s simple, safe, and efficient.

You may also like...

Leave a Reply

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