Bird
Raised Fist0
Kotlinprogramming~5 mins

Coroutine scope and structured concurrency in Kotlin

Choose your learning style10 modes available
Introduction

Coroutine scope helps manage coroutines by grouping them together. Structured concurrency makes sure coroutines finish properly and errors are handled safely.

When you want to run multiple tasks at the same time and keep track of them.
When you need to cancel all related tasks if one fails or if the user leaves a screen.
When you want to avoid memory leaks by automatically stopping coroutines when they are no longer needed.
When you want to organize your code so that background work is easy to control and understand.
Syntax
Kotlin
fun main() = runBlocking {
    launch {
        // coroutine work here
    }
}

runBlocking creates a coroutine scope that blocks the main thread until all coroutines inside finish.

launch starts a new coroutine inside the scope.

Examples
This example runs a coroutine that prints a message inside the main blocking scope.
Kotlin
fun main() = runBlocking {
    launch {
        println("Hello from coroutine")
    }
}
This example launches a coroutine that repeats work 3 times and waits for it to finish using join().
Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        repeat(3) { i ->
            println("Coroutine working: $i")
            delay(100)
        }
    }
    job.join() // wait for coroutine to finish
}
This shows structured concurrency: the parent coroutine waits for its child coroutine before finishing.
Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking {
    val parentJob = launch {
        launch {
            delay(100)
            println("Child coroutine done")
        }
        println("Parent coroutine done")
    }
    parentJob.join()
}
Sample Program

This program shows a main coroutine that launches a child coroutine. The main waits for the child to finish before ending.

Kotlin
import kotlinx.coroutines.*

fun main() = runBlocking {
    println("Start main coroutine")

    val job = launch {
        println("Start child coroutine")
        delay(500)
        println("Child coroutine finished")
    }

    println("Waiting for child coroutine")
    job.join() // wait for child coroutine to finish
    println("Main coroutine finished")
}
OutputSuccess
Important Notes

Always use coroutine scopes to keep your coroutines organized and avoid leaks.

Structured concurrency means child coroutines are tied to their parent and cancel or complete together.

Use runBlocking only in main functions or tests; in apps, use lifecycle-aware scopes.

Summary

Coroutine scopes group coroutines to manage their lifecycle.

Structured concurrency ensures child coroutines finish before their parent.

This helps write safe, clear, and leak-free asynchronous code.

Practice

(1/5)
1. What is the main purpose of a CoroutineScope in Kotlin?
easy
A. To block the main thread until coroutines finish
B. To create threads manually for parallel execution
C. To group coroutines and manage their lifecycle together
D. To convert coroutines into synchronous functions

Solution

  1. Step 1: Understand CoroutineScope role

    A CoroutineScope groups coroutines so they can be managed as one unit.
  2. Step 2: Compare other options

    The other options describe unrelated or incorrect behaviors for CoroutineScope.
  3. Final Answer:

    To group coroutines and manage their lifecycle together -> Option C
  4. Quick Check:

    CoroutineScope groups coroutines [OK]
Hint: CoroutineScope manages coroutines lifecycle as a group [OK]
Common Mistakes:
  • Thinking CoroutineScope creates threads
  • Confusing CoroutineScope with blocking calls
  • Assuming CoroutineScope converts coroutines to sync
2. Which of the following is the correct way to launch a coroutine within a CoroutineScope?
easy
A. scope.launch { /* coroutine code */ }
B. launch.scope { /* coroutine code */ }
C. CoroutineScope.launch { /* coroutine code */ }
D. scope.run { /* coroutine code */ }

Solution

  1. Step 1: Recall coroutine launch syntax

    Within a CoroutineScope, you call launch as a function on the scope instance.
  2. Step 2: Check options for syntax correctness

    scope.launch { /* coroutine code */ } uses scope.launch {} which is correct. Others misuse syntax or functions.
  3. Final Answer:

    scope.launch { /* coroutine code */ } -> Option A
  4. Quick Check:

    launch is called on CoroutineScope instance [OK]
Hint: Use scope.launch { } to start coroutine inside scope [OK]
Common Mistakes:
  • Swapping order like launch.scope
  • Using run instead of launch
  • Calling launch as a static method
3. What will be the output of this Kotlin code snippet?
import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        delay(100)
        println("Task done")
    }
    println("Waiting")
    job.join()
    println("Finished")
}
medium
A. Task done\nWaiting\nFinished
B. Waiting\nTask done\nFinished
C. Waiting\nFinished\nTask done
D. Finished\nWaiting\nTask done

Solution

  1. Step 1: Analyze coroutine launch and delay

    The coroutine launched delays 100ms before printing "Task done". Meanwhile, "Waiting" prints immediately.
  2. Step 2: Understand job.join() effect

    The main coroutine waits for the launched job to finish before printing "Finished".
  3. Final Answer:

    Waiting\nTask done\nFinished -> Option B
  4. Quick Check:

    Output order respects delay and join [OK]
Hint: join() waits for coroutine to finish before continuing [OK]
Common Mistakes:
  • Assuming launched coroutine runs instantly
  • Ignoring delay effect
  • Printing Finished before job completes
4. Identify the problem in this Kotlin coroutine code and choose the correct fix:
fun main() = runBlocking {
    val job = GlobalScope.launch {
        delay(1000)
        println("Done")
    }
    println("Waiting")
}
medium
A. Replace delay(1000) with Thread.sleep(1000)
B. Use CoroutineScope().launch {} instead of GlobalScope.launch
C. Remove runBlocking and use GlobalScope.launch only
D. Add job.join() after println("Waiting")

Solution

  1. Step 1: Identify lifecycle issue with GlobalScope

    Using GlobalScope.launch starts coroutine that may outlive runBlocking, so "Done" may never print.
  2. Step 2: Fix by waiting for job completion

    Calling job.join() ensures main coroutine waits for launched coroutine to finish before exiting.
  3. Final Answer:

    Add job.join() after println("Waiting") -> Option D
  4. Quick Check:

    join() waits for coroutine to complete [OK]
Hint: Always join launched jobs to wait for completion [OK]
Common Mistakes:
  • Ignoring job.join() causing premature exit
  • Replacing delay with blocking sleep
  • Removing runBlocking causing main to exit early
5. Given this Kotlin code using structured concurrency, what will be printed?
import kotlinx.coroutines.*

fun main() = runBlocking {
    try {
        coroutineScope {
            launch {
                delay(100)
                println("Child 1 done")
            }
            launch {
                delay(50)
                throw RuntimeException("Error in Child 2")
            }
        }
    } catch (e: Exception) {
        println("Caught: " + e.message)
    }
    println("End of main")
}
hard
A. Caught: Error in Child 2\nEnd of main
B. Child 1 done\nCaught: Error in Child 2\nEnd of main
C. Caught: Error in Child 2
D. Child 1 done\nEnd of main

Solution

  1. Step 1: Understand coroutineScope behavior on exceptions

    If any child coroutine throws an exception, coroutineScope cancels all children and throws the exception.
  2. Step 2: Analyze timing and cancellation

    Child 2 throws after 50ms, cancelling Child 1 before it prints. The exception is caught and message printed.
  3. Final Answer:

    Caught: Error in Child 2\nEnd of main -> Option A
  4. Quick Check:

    Exception cancels siblings, caught prints message [OK]
Hint: Exception cancels sibling coroutines in coroutineScope [OK]
Common Mistakes:
  • Assuming Child 1 prints despite cancellation
  • Missing try-catch around coroutineScope
  • Thinking exceptions are ignored in coroutineScope
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard