Reputation: 14320
I am trying to understand coroutines in Kotlin, but I've hit a bit of a roadblock. In the following example I would expect the following to happen:
But it prints this:
0
3
2
1
4
5
6
I don't really understand why this is happening. I mostly don't understand how the output of job2
can come before 4
. I am very confused.
println("0")
runBlocking {
val job = GlobalScope.launch {
// launch new coroutine and keep a reference to its Job
delay(1200L)
println("1")
}
val job2 = GlobalScope.launch {
// launch new coroutine and keep a reference to its Job
delay(1000L)
println("2")
}
println("3")
job.join() // wait until child coroutine completes
println("4")
job2.join() // wait until child coroutine
println("5")
}
println("6")
Upvotes: 2
Views: 903
Reputation: 6803
This is what happens:
runBlocking
, which blocks the current thread until the block is finished.job.join()
).job2.join()
). This returns immediately, as job2 has already finished.You may read https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html to get a better insight into suspending functions. What helped me understand coroutines was this video: https://www.youtube.com/watch?v=_hfBv0a09Jc
Upvotes: 4
Reputation: 20112
Reading from the documentation of kotlinx.coroutines#launch:
By default, the coroutine is immediately scheduled for execution. Other start options can be specified via start parameter. See CoroutineStart for details. An optional start parameter can be set to CoroutineStart.LAZY to start coroutine lazily. In this case, the coroutine Job is created in new state. It can be explicitly started with start function and will be started implicitly on the first invocation of join.
So your coroutine starts immediate after the launch
command. This should explain the order of executed commands. The delay
in your async coroutines is executed right away while the main thread executes the next statements. 3
before 2
before 1
. Then you wait until your first job is finished (printing 1
) before printing 4
from the main thread.
If you want your code to be executed like you expect it, you can add the start = CoroutineStart.LAZY
parameter to the launch
like this:
println("0")
runBlocking {
val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
// launch new coroutine and keep a reference to its Job
delay(1200L)
println("1")
}
val job2 = GlobalScope.launch(start = CoroutineStart.LAZY) {
// launch new coroutine and keep a reference to its Job
delay(1000L)
println("2")
}
println("3")
job.join() // wait until child coroutine completes
println("4")
job2.join() // wait until child coroutine
println("5")
}
println("6")
Upvotes: 3