Working with blocking code

Coroutines work well together to achieve non-blocking code. At some point, however, it's likely that the code will need to interact with traditional, sequential blocking code. We can illustrate this by revisiting out working example:

fun main() {
GlobalScope.launch {
delay(500)
println("Coroutines")
}
println("Hello")
Thread.sleep(1000)
}

In the preceding code, we are launching our coroutine from our standard main() function. However, the main() function isn't aware of any coroutines, so we have to call Thread.sleep() to prevent the termination of that function before our coroutine finishes. This mirrors the simple examples given at the beginning of this chapter using Thread and a short delay. However, for a non-trivial example such as loading network data, relying on some predefined delay is not feasible.

For uses cases such as network requests or database operations, we could use the runBlocking() coroutine builder we mentioned previously:

fun main() = runBlocking {
GlobalScope.launch {
delay(500) // simulate network request
println("Coroutines")
}
println("Hello")
}

With this change, our main() function will not complete until all the coroutines within the scope of runBlocking() complete. If we run this code right now, we will get the following output:

Hello

Notice that we aren't seeing the result of our coroutine, which should be printing out Coroutines. This is because that coroutine is launched using GlobalScope rather than the scope of runBlocking(). Because our coroutine is scoped within GlobalScope, the scope associated with runBlocking() completes because it has no active coroutines, which is why we aren't seeing the result from our launched coroutine.

Let's change that behavior in the following snippet:

fun main() = runBlocking {
launch {
delay(500)
println("Coroutines")
}
println("Hello")
}

Now that we are launching our coroutine within the same scope that our main() function is associated with, we can see the following correct output:

Hello
Coroutines

By making use of the runBlocking() coroutine builder, we can connect our blocking and non-blocking code with minimal changes.