Up until now, to let our asynchronous code complete, we've used either Thread.sleep() or CountDownLatch. But there are better options with threads and coroutines. Much like Thread, a job has the join() function. By invoking it, we can wait for the execution of the coroutine to complete.
Take a look at the following code:
val j = launch(CommonPool) {
for (i in 1..10_000) {
if (i % 1000 == 0) {
println(i)
yield()
}
}
}
Although it should have printed 10 lines, it doesn't print anything, actually. That's because our main thread terminates before giving a coroutine a chance to start.
By adding the following lines, our example will print the expected results:
runBlocking {
j.join()
}
What about this runBlocking, you ask? Remember that we could call yield() only from another coroutine because it's a suspending function? The same is true for join(). Since our main method is not a coroutine, we need to have a bridge between our regular code, that is not a suspending function and coroutines. This function does exactly that.