Skip to main content

Kotlin Coroutines

In the world of Kotlin, Coroutines are king. They are lightweight threads that allow for efficient and non-blocking asynchronous programming. Coroutines are an elegant way of handling long-running tasks that might otherwise block the main thread and cause your application to freeze. In this tutorial, we will cover what Coroutines are, how to use them, and why they are beneficial for your Kotlin development.

What are Coroutines?

Coroutines are a way of writing asynchronous code in a more linear, understandable way. They allow you to write asynchronous code as if it were synchronous, making it easier to read and understand. Coroutines are essentially lightweight threads; they are launched with a launch keyword and can be thought of as a small piece of work that can be run concurrently with other pieces of work.

Coroutine Basics

The most basic way to create a Coroutine is to use the launch function:

import kotlinx.coroutines.*

fun main() {
GlobalScope.launch { // launch a new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main thread continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

This program will print "Hello," immediately, delay for a second, and then print "World!". This is because the launch function starts a new Coroutine which runs concurrently with the rest of the program.

Structured Concurrency

In real-world applications, you will want to use structured concurrency to create Coroutines. This means that you will create a CoroutineScope and launch Coroutines within that scope. When the scope is cancelled or completes, all Coroutines within that scope will also be cancelled or complete.

fun main() = runBlocking { // this: CoroutineScope
launch { // launch a new coroutine and keep a reference to its Job
delay(1000L)
println("World!")
}
println("Hello,") // main coroutine continues here immediately
} // this is your first coroutine scope. It gets cancelled when your main coroutine is done.

In the above example, we create a runBlocking CoroutineScope. This is a scope that blocks the main thread until all of its children Coroutines complete.

Coroutine Builders

There are three primary Coroutine builders in Kotlin: launch, async, and runBlocking.

  • launch: Launches a new Coroutine without blocking the current thread and returns a reference to the Coroutine as a Job.

  • async: Starts a new Coroutine and returns its future result as an implementation of Deferred<T>.

  • async is designed to be used with the await function, which suspends the Coroutine until the result is available.

  • runBlocking: Blocks the current thread until its CoroutineScope completes. This is typically used at the top-level of a program or in tests.

fun main() = runBlocking<Unit> { 
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}

Conclusion

Coroutines are a powerful feature in Kotlin that allow for efficient, non-blocking asynchronous programming. They allow you to write long-running code in a more linear, understandable way, and can be used in a structured way with CoroutineScopes. Whether you're writing a server-side application, a UI on Android, or any other type of application, Coroutines can help you write efficient, easy-to-read code.

Coroutines are a vast topic and we have just scratched the surface. We will continue to explore more advanced topics like Coroutine Context, Dispatchers, and Exception Handling in future tutorials. Practice what you have learned so far and try to incorporate Coroutines in your Kotlin projects. Happy Kotlin-ing!