How does Kotlin Coroutines handle structured concurrency?
We’ll dive into the world of Kotlin coroutines and explore how they handle structured concurrency. Don’t worry if you’re not a technical person; I’ll make sure to explain everything clearly and give real-life examples to make it easier to understand.
Let say you’re a manager at a restaurant, and you need to handle multiple tasks efficiently to keep things running smoothly. Each task represents a customer order, and you have a team of chefs to help you out. Instead of managing each order separately, you decide to use a structured approach.

Kotlin coroutines work so similar to this example. They help you manage multiple tasks concurrently without the hassle of dealing with low-level threading details. With structured concurrency, you can group coroutines into scopes. A scope ensures that all coroutines within it complete before it terminates, preventing any accidental leaks or runaway coroutines.
Let’s say you want to
fetch data from multiple APIs and update the UI with the results.
You create a coroutine scope for this task.
If any of the coroutines fail or are canceled, the entire scope will be canceled, ensuring a clean and predictable behavior.
import kotlinx.coroutines.*
fun main() {
runBlocking {
// Create a coroutine scope
val scope = CoroutineScope(Dispatchers.Default)
scope.launch {
// Coroutine 1: Fetch data from API 1
// ...
}
scope.launch {
// Coroutine 2: Fetch data from API 2
// ...
}
// Wait for all coroutines to complete
scope.coroutineContext.job.join()
}
}Let’s explore a real-life scenario of downloading images concurrently from multiple URLs using Kotlin coroutines. I’ll explain the code step by step for a beginner coder.
Scenario: Downloading Images Concurrently
import kotlinx.coroutines.*
import java.io.File
import java.net.URL
fun main() {
// List of image URLs
val imageUrls = listOf(
"https://example.com/image1.jpg",
"https://example.com/image2.jpg",
"https://example.com/image3.jpg"
)
// Function to download an image from a URL
suspend fun downloadImage(url: String, destination: String) {
try {
val image = URL(url).readBytes()
File(destination).writeBytes(image)
println("Image downloaded: $destination")
} catch (e: Exception) {
println("Failed to download image from $url: ${e.message}")
}
}
runBlocking {
// Create a coroutine scope
val scope = CoroutineScope(Dispatchers.Default)
// Launch a coroutine for each image download
val jobs = imageUrls.mapIndexed { index, url ->
val fileName = "image_$index.jpg"
scope.launch {
downloadImage(url, fileName)
}
}
// Wait for all coroutines to complete
jobs.forEach { it.join() }
println("All images downloaded and saved to disk")
}
}
We start by creating a list imageUrls containing the URLs of the images we want to download.
Next, we define a suspend function downloadImage(url: String, destination: String). This function takes a URL and a destination file path and is marked with suspend because it performs a network operation, which is a suspending function.
inside the downloadImage function, we try to download the image from the given URL using the URL class and readBytes() method. Then, we write the downloaded image bytes to a file with the specified destination.
In case of any exceptions during the download, we catch them and print an error message.
In the main() function, we use runBlocking to create the main coroutine that will block the program execution until all other coroutines complete.
We create a CoroutineScope with the Dispatchers.Default context. This context is suitable for CPU-intensive tasks like network operations.
We use mapIndexed to iterate over the imageUrls list and launch a new coroutine for each image download. The mapIndexed function returns a list of Job instances, representing each coroutine.
Each coroutine runs the downloadImage function, passing the URL and a unique file name for each image.
After launching all coroutines, we use forEach to call join() on each Job instance. This ensures that the main coroutine waits for all image downloads to complete before moving on.
Finally, we print a message indicating that all images have been downloaded and saved to disk.
So what we did guys in this example ?
We used Kotlin coroutines to download images concurrently from multiple URLs.
The structured concurrency provided by coroutines ensures that all the image downloads complete successfully, and any exceptions are handled gracefully.
Hey there, my amazing Medium followers! I’ve got something exciting to share with you. If you’re hungry for more programming and personal growth goodness, you’ve got to check out my website.
