Skip to main content
Kotlin Basics
CHAPTER 23 Beginner

Coroutines in Kotlin

Updated: May 18, 2026
5 min read

# CHAPTER 23

Coroutines in Kotlin

1. Chapter Introduction

If you build an Android app and make a network request to download an image on the Main UI Thread, the app will freeze. If the download takes 5 seconds, the user cannot scroll or click for 5 seconds. The OS will likely crash the app with an "ANR" (Application Not Responding) error. To fix this, we must run heavy tasks in the background. Traditionally, this was done using OS Threads, which are heavy and complex. Kotlin solves this elegantly with Coroutines—lightweight "green threads" that make asynchronous programming as simple as writing sequential code.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the difference between OS Threads and Coroutines.
  • Define and call suspend functions.
  • Launch background tasks using GlobalScope.launch.
  • Return data from background tasks using async and await.
  • Use delay() to yield execution.

3. What is a Coroutine?

A Coroutine is a concurrency design pattern. Think of it as a very lightweight thread. You can run 100,000 coroutines simultaneously on a single standard CPU without crashing your computer because they do not map 1:1 to heavy OS threads. They "suspend" (pause) when waiting for data, freeing the underlying thread to do other work!

*Note: Coroutines require an external library. In a Gradle project, you add org.jetbrains.kotlinx:kotlinx-coroutines-core.*

4. The launch Builder

The simplest way to start a coroutine is launch. It follows the "fire and forget" principle—it starts a background task and doesn't return a result.
kotlin
12345678910111213141516
import kotlinx.coroutines.*

fun main() {
    println("Main thread started.")

    // Start a coroutine in the background
    GlobalScope.launch {
        delay(1000L) // Non-blocking sleep for 1 second!
        println("Hello from the Coroutine!")
    }

    println("Main thread is doing other work...")
    
    // We must sleep the main thread so it doesn't close before the coroutine finishes
    Thread.sleep(2000L) 
}

*Output:*

123
Main thread started.
Main thread is doing other work...
Hello from the Coroutine!

5. Suspend Functions

A suspend function is a special function that can be paused and resumed later. delay() is a suspend function. *Rule: Suspend functions can ONLY be called from a coroutine or another suspend function.*
kotlin
123456789101112
// Mark the function with 'suspend'
suspend fun downloadData(): String {
    println("Downloading started...")
    delay(2000L) // Simulating a slow network
    return "Data Payload"
}

fun main() = runBlocking { 
    // runBlocking creates a coroutine that blocks the main thread until it finishes
    val result = downloadData()
    println(result)
}

6. async and await

If you need to run multiple background tasks simultaneously AND you need them to return data, you use async. async returns a Deferred object (similar to a Future or Promise in other languages). You call .await() to get the result.
kotlin
1234567891011121314151617181920212223
import kotlinx.coroutines.*

suspend fun fetchWeather(): String {
    delay(1000L)
    return "Sunny, 72F"
}

suspend fun fetchNews(): String {
    delay(1000L)
    return "Kotlin is awesome!"
}

fun main() = runBlocking {
    // Both start at the exact same time!
    val weatherDeferred = async { fetchWeather() }
    val newsDeferred = async { fetchNews() }

    // Wait for both to finish
    println("Weather: ${weatherDeferred.await()}")
    println("News: ${newsDeferred.await()}")
    
    // Total time is 1 second, not 2 seconds!
}

7. Mini Project: Async Task Runner

kotlin
12345678910111213141516
import kotlinx.coroutines.*

fun main() = runBlocking {
    println("Starting App...")
    
    val job = launch {
        println("Task 1 running...")
        delay(500L)
        println("Task 1 complete.")
    }
    
    println("App UI is active...")
    
    job.join() // Waits specifically for this job to finish
    println("App Closing.")
}

8. Common Mistakes

  • Using Thread.sleep() inside a Coroutine: Thread.sleep blocks the actual OS thread, freezing everything. delay() suspends the coroutine, allowing the OS thread to execute other coroutines. Never use Thread.sleep inside a coroutine.
  • Calling suspend functions from normal functions: The compiler will throw an error. A suspend function must be inside a launch, async, or runBlocking block.

9. Best Practices

  • Avoid GlobalScope: In production Android apps, never use GlobalScope.launch. If the user closes the app, a GlobalScope coroutine keeps running in the background, draining the battery! Use lifecycle-aware scopes like viewModelScope or lifecycleScope.

10. Exercises

  1. 1. Write a suspend fun calculateScore(): Int that delays for 2 seconds and returns 100.
  1. 2. Inside fun main() = runBlocking, call it and print the result.

11. MCQs with Answers

Question 1

What is a major problem with running heavy tasks on the Main Thread in Android?

Question 2

What is a Kotlin Coroutine?

Question 3

Which coroutine builder is used for "fire and forget" background tasks that do not return a result?

Question 4

What keyword is required to define a function that can be paused and resumed later?

Question 5

Where is the ONLY place a suspend function can be called?

Question 6

What function is the coroutine equivalent of Thread.sleep(), but safely yields the thread instead of blocking it?

Question 7

If a background task needs to return data, which coroutine builder should you use?

Question 8

What method must you call on the result of an async block to retrieve the actual data?

Q9. Does runBlocking block the main thread? a) Yes, it bridges regular synchronous code with async coroutine code by blocking the thread until all its internal coroutines finish b) No, it is non-blocking Answer: a) Yes, it blocks the thread.
Question 10

Why is GlobalScope dangerous in Android development?

12. Interview Questions

  • Q: Contrast Coroutines with OS Threads. Why can you spawn 100,000 Coroutines but not 100,000 OS Threads?
  • Q: Explain the difference between launch and async.

13. Summary

Coroutines completely modernize asynchronous programming. By removing the "callback hell" associated with Java threads and RxJava, Kotlin allows developers to write async network calls and database queries in a sequential, top-to-bottom style using suspend and await. It is the definitive way to handle concurrency on the JVM.

14. Next Chapter Recommendation

We've mentioned Android many times because Kotlin and Android are deeply intertwined. In Chapter 24: Kotlin for Android Basics, we will step away from the console and look at how Kotlin is applied to build mobile apps.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·