Coroutine builders are functions that help us create a coroutine. They can be called from normal functions because they do not suspend themselves.
The kotlinx.coroutines
library provides the three most essential coroutine builders:
launch
async
runBlocking
Let’s explore them one by one.
launch
builderThe launch
builder is an essential kotlin coroutine builder. It works on the “fire and forgets” approach meaning that upon launch, a new coroutine will be created, and it will not return anything to its caller. The started coroutine will keep working in the background.
import kotlinx.coroutines.GlobalScopeimport kotlinx.coroutines.delayimport kotlinx.coroutines.launchfun main() {GlobalScope.launch {delay(1000L)println("First Coroutine")}GlobalScope.launch {delay(1000L)println("Second Coroutine")}GlobalScope.launch {delay(1000L)println("Third Coroutine")}println("Hello,")Thread.sleep(2000L)}
Lines 1–3: We import the kotlinx.coroutines
packages.
Lines 6–8: The first coroutine will be launched in the background here, but the main function will not stop.
Lines 10–13: The second coroutine will be launched in the background here, but the main function will keep working in the meantime.
Lines 14–17: The third coroutine will be launched in the background here, but the main function will keep working in the meantime.
Line 18: Print the Hello
statement, and then First Coroutine
, Second Coroutine
, and Third Coroutine
will be printed in that order.
async
builderThe async
and launch
builders are very similar, but unlike launch
it returns a Deferred <T>
object which is the equivalent of a promise. We can call the suspending function await
on the deferred value to wait and get the result.
import kotlinx.coroutines.*fun main() = runBlocking {val resultDeferred: Deferred<Int> = GlobalScope.async {delay(1000L)return 5}val result: Int = resultDeferred.await()println(resultDeferred.await())}
In the above example, the returned value is 5
and its datatype is int
. The Deffered<int>
is returned, and the await
function will wait for the result 5
.
Similar to the launch
builder, async
start a coroutine right away. It is a method for starting several processes at once and then wait for the outcome.
runBlocking
builderAs the name implies, the runBlocking
coroutine builder, blocks the main thread until each of the coroutine's tasks completed, that the main thread is created.
We normally use runBlocking
in the main thread when we are running tests to ensure the test doesn't end while doing heavy computation in the test-suspended functions.
import kotlinx.coroutines.delayimport kotlinx.coroutines.runBlockingfun main() {runBlocking {delay(1000L)println("First Coroutine")}runBlocking {delay(1000L)println("Second Coroutine")}runBlocking {delay(1000L)println("Third Coroutine")}println("Print Order")}
Lines 1–2: Import the kotlinx.coroutines
packages.
Lines 5–7: The first coroutine will be launched here, and the First Coroutine
will be printed with a 1-second delay.
Lines 9–11: The second coroutine will be launched here, and Second Coroutine
will be printed with a 1-second delay.
Lines 13 – 15: The third coroutine will be launched here, and Third Coroutine
will be printed with a 1-second delay.
Line 17: Print Order
statement will be printed in last.
Coroutines are launched in coroutine builders and are bound by a coroutine scope. A lazy way to launch a coroutine would be to use the GlobalScope
. This means the coroutine will be running for as long as the application is running, and if there is no important reason to do this, it’s a way to misuse resources.
In launching coroutines, we would use the launch
keyword like this:
...GlobalScope.launch{doSomething() // does some heavy computation in the background... do other stuff}...suspend fun doSomething(){// heavy computation here}
However, as stated earlier, we don’t want to launch coroutines in the GlobalScope
. When launching a coroutine, we want to be sure that we do it right to avoid coroutine leaks that will cause us to run out of memory.
Launching coroutines in GlobalScope
, and forgetting to keep a reference so that we can manually cancel later, could be as error-prone as using callbacks. How do we solve this problem? That’s where structured concurrency comes in.