advanced20 min

Coroutines Fundamentals

An introduction to Kotlin's suspend functions and coroutines for asynchronous code.

What you'll learn

  • Explain what a suspend function is and why it's needed for asynchronous code
  • Describe conceptually how a coroutine differs from a traditional thread
  • Recognize launch and runBlocking as ways to start coroutine execution

Explanation

Kotlin's concurrency model is built on coroutines -- lightweight units of concurrent execution that can be paused and resumed without blocking the underlying thread. A function that can pause is marked suspend: suspend fun fetchData(): String { ... } -- this marks it as a function that may suspend execution (e.g. while waiting for network I/O) without blocking the thread it's running on.

A key conceptual difference from a traditional OS thread: a single thread can run many coroutines, switching between them at suspension points, which is far cheaper than creating a new thread per concurrent task -- similar in spirit (though technically different in implementation) to Go's goroutines from earlier language comparisons if you've seen those.

You start a coroutine with a coroutine builder like launch (fire-and-forget, inside a CoroutineScope) or, in simple example/test code, runBlocking (which blocks the current thread until the coroutine inside it completes -- mainly used to bridge into coroutine code from regular, non-suspending code, like a program's main function).

This is an introductory conceptual overview -- production coroutine code (structured concurrency, dispatchers, cancellation) is a deeper topic beyond this fundamentals course's scope.

Guided lab

Predict: A suspend function bridged via runBlocking

KotlinNot executed
This lab does not run in your browser or on VisaSparkSchools's servers. Read the code, predict what it does, then reveal the real expected output.

Read this program (using kotlinx.coroutines' runBlocking and delay) and predict exactly what it prints, in order.

import kotlinx.coroutines.*

suspend fun fetchGreeting(): String {
    delay(100) // simulates a non-blocking wait, e.g. for network I/O
    return "Hello from a coroutine!"
}

fun main() = runBlocking {
    println("Before fetch")
    val greeting = fetchGreeting()
    println(greeting)
    println("After fetch")
}

Stuck? Get a hint.

Common mistakes

  • Calling a suspend function directly from regular (non-suspend) code without a coroutine builder like launch or runBlocking -- it won't compile.
  • Assuming a coroutine is the same as an OS thread -- many coroutines can run on one thread, switching at suspension points.
  • Using runBlocking in production code paths instead of just examples/tests/bridging code -- it blocks the calling thread, defeating the point of coroutines' non-blocking nature.

Knowledge check

Knowledge check

1. What does the `suspend` keyword on a function indicate?
2. How do coroutines relate to OS threads?
3. What is `runBlocking` typically used for?

Takeaway

suspend functions can pause without blocking their thread; many coroutines can share one thread; use runBlocking mainly to bridge into coroutine code from regular code.

Summary

Coroutines are lightweight, pausable units of concurrency built on suspend functions, started via builders like launch or runBlocking -- introductory concepts only in this course.

References

Your notes

Notes save automatically.

Finished this lesson?

Mark it complete to track your progress and schedule a future review.