📖 Scenario: You are building a simple Kotlin program that uses coroutines to perform tasks concurrently in a safe and organized way. This helps avoid problems like tasks running forever or leaking resources.
🎯 Goal: Learn how to create a CoroutineScope, launch coroutines inside it, and use structured concurrency to wait for all tasks to finish before ending the program.
📋 What You'll Learn
Create a CoroutineScope using runBlocking
Launch two coroutines inside the scope that print messages after delays
Use structured concurrency to wait for both coroutines to complete
Print a final message after all coroutines finish
💡 Why This Matters
🌍 Real World
Coroutines help write programs that do many things at once without freezing or crashing. This is useful in apps that load data, handle user input, or do background work.
💼 Career
Understanding coroutine scopes and structured concurrency is essential for Kotlin developers working on Android apps, backend services, or any system that needs efficient multitasking.
Progress0 / 4 steps
1
Create a CoroutineScope with runBlocking
Write a Kotlin program that creates a CoroutineScope using runBlocking. Inside it, write a comment // Coroutine scope started to mark the scope start.
Kotlin
Hint
Use fun main() = runBlocking { } to create the coroutine scope.
2
Launch two coroutines inside the scope
Inside the runBlocking scope, launch two coroutines using launch. The first coroutine should delay 500 milliseconds and then print "First coroutine done". The second coroutine should delay 300 milliseconds and then print "Second coroutine done".
Kotlin
Hint
Use launch { delay(500L); println("First coroutine done") } and similarly for the second coroutine.
3
Use structured concurrency to wait for coroutines
Modify the program so that the runBlocking scope waits for both launched coroutines to finish before continuing. Use the fact that launch returns a Job and call join() on both jobs.
Kotlin
Hint
Save the result of launch in variables and call join() on them to wait.
4
Print a final message after all coroutines finish
After waiting for both coroutines to finish, print "All coroutines completed" inside the runBlocking scope.
Kotlin
Hint
Use println("All coroutines completed") after joining both jobs.
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
Step 1: Understand CoroutineScope role
A CoroutineScope groups coroutines so they can be managed as one unit.
Step 2: Compare other options
The other options describe unrelated or incorrect behaviors for CoroutineScope.
Final Answer:
To group coroutines and manage their lifecycle together -> Option C
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
Step 1: Recall coroutine launch syntax
Within a CoroutineScope, you call launch as a function on the scope instance.
Step 2: Check options for syntax correctness
scope.launch { /* coroutine code */ } uses scope.launch {} which is correct. Others misuse syntax or functions.
Final Answer:
scope.launch { /* coroutine code */ } -> Option A
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
Step 1: Analyze coroutine launch and delay
The coroutine launched delays 100ms before printing "Task done". Meanwhile, "Waiting" prints immediately.
Step 2: Understand job.join() effect
The main coroutine waits for the launched job to finish before printing "Finished".
Final Answer:
Waiting\nTask done\nFinished -> Option B
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
Step 1: Identify lifecycle issue with GlobalScope
Using GlobalScope.launch starts coroutine that may outlive runBlocking, so "Done" may never print.
Step 2: Fix by waiting for job completion
Calling job.join() ensures main coroutine waits for launched coroutine to finish before exiting.
Final Answer:
Add job.join() after println("Waiting") -> Option D
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?