Home » Kotlin coroutine async example

Kotlin coroutine async example

Kotlin coroutine async example

1. Overview

In this example, we will learn about the Kotlin coroutine async example.

2. Kotlin Coroutine

A coroutine is a concurrency design pattern you can use to simplify code that executes asynchronously.

It takes a block of code to run, that works concurrently with the rest of the code. However, it is not bound to any thread. It may suspend its execution in one thread and resume in another one.

Kotlin coroutines are extremely inexpensive when compared with threads. Each time when we want to start a new task asynchronously, we can create a new coroutine. To start a new coroutine, we use one of the main “coroutine builders”: launchasync, or runBlocking.

JetBrains developed the rich kotlinx.coroutines library as part of version 1.3 for coroutines.

3. Kotlin async coroutine

The async creates a coroutine and can return the result of the asynchronous task. This returns a reference to the coroutine as a Deferred<T> whereas T refers to the type of the result. You can use await or awaitAll to wait and retrieve the result.

5. Kotlin coroutine async example

Creates a coroutine and returns its future result as an implementation of Deferred. Deferred<T> can return results of type T from the asynchronous task.

fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext, 
    start: CoroutineStart = CoroutineStart.DEFAULT, 
    block: suspend CoroutineScope.() -> T
): Deferred<T>

For example, the following async method returns a string as output. You can wait for the result using the await or awaitAll method.

fun main()  = runBlocking() {
    println("main(): ${Thread.currentThread().name}")
    val deferred: Deferred<String> = async { 
                println("async: ${Thread.currentThread().name}")
                println("async:  ${Thread.currentThread().name}")
                "Hello World"
    }
   val result = deferred.await()
   println(result)
   println("main(): ${Thread.currentThread().name}")
}
/* prints
main(): main @coroutine#1
async corotine: DefaultDispatcher-worker-1 @coroutine#2
async corotine:  DefaultDispatcher-worker-1 @coroutine#2
Hello World
main(): main @coroutine#1 
*/

5.1. Cancel the async coroutine

You can cancel the running coroutine by calling the cancel method on the deferred object.

fun main()  = runBlocking() {
    println("main(): ${Thread.currentThread().name}")
    val deferred: Deferred<String> = async { 
                println("async: ${Thread.currentThread().name}")
                println("async:  ${Thread.currentThread().name}")
                "Hello World"
    }
   deferred.cancel()
    println("main(): ${Thread.currentThread().name}")
}
/* prints
main(): main @coroutine#1
main(): main @coroutine#1 
*/

5.2. Start Kotlin async coroutine lazily

By default, the coroutine is immediately scheduled for execution.

However, you can customize the start option by using the start parameter.

For example, the following launch coroutine builder contains the start parameter as CoroutineStart.LAZY to start coroutine lazily. Here, the returned coroutine Deferred is in the new state initially and later we explicitly started the coroutine by invoking the start function of the Deferred.

fun main()  = runBlocking() {
    println("main() method: ${Thread.currentThread().name}")
    val deferred: Deferred<String> = async(Dispatchers.Default, CoroutineStart.LAZY) { 
                println("async corotine: ${Thread.currentThread().name}")
                println("async corotine:  ${Thread.currentThread().name} ")
                "Hello World"
    }
   deferred.start()
   val result = deferred.await()
   println(result)
   println("main() method on ${Thread.currentThread().name}")
}
/* prints
main() method: main @coroutine#1
async corotine: DefaultDispatcher-worker-1 @coroutine#2
async corotine:  DefaultDispatcher-worker-1 @coroutine#2
Hello World
main() method on main @coroutine#1
*/

5.3. Coroutine async exception

It cancels the parent job (or outer scope) on failure to enforce a structured concurrency paradigm.

For example, the following child async throws an uncaught exception and results in the parent’s cancellation. To change that behavior, you can use the supervising parent SupervisorJob or supervisorScope. See this article, to learn about the SupervisorJob.

fun main()  {
    runBlocking {
        async {
    		println("parent launch: ${Thread.currentThread().name}")
            val deferred: Deferred<Unit> = async { 
                println("Launch corotine: ${Thread.currentThread().name}")
                val i = 100/0    // throw exception  
                println("Launch corotine:  ${Thread.currentThread().name}")
            }
            deferred.join()
    		println("parent launch: ${Thread.currentThread().name} ")
        }
    }
}
/* prints
parent launch: main @coroutine#2 
Launch corotine: main @coroutine#3 
Exception in thread "main" java.lang.ArithmeticException: / by zero
 at FileKt$main$1$1$deferred$1.invokeSuspend (File.kt:14) 
 at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) 
 at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106) 
*/

6. Conclusion

To sum up, we have learned the Kotlin coroutine async example.

Leave a Reply

Your email address will not be published.