Unconfined

A coroutine dispatcher that is not confined to any specific thread. It executes the initial continuation of a coroutine in the current call-frame and lets the coroutine resume in whatever thread that is used by the corresponding suspending function, without mandating any specific threading policy. Nested coroutines launched in this dispatcher form an event-loop to avoid stack overflows.

Event loop

Event loop semantics is a purely internal concept and has no guarantees on the order of execution except that all queued coroutines will be executed on the current thread in the lexical scope of the outermost unconfined coroutine.

For example, the following code:

withContext(Dispatchers.Unconfined) {
println(1)
launch(Dispatchers.Unconfined) { // Nested unconfined
println(2)
}
println(3)
}
println("Done")

Can print both "1 2 3" and "1 3 2". This is an implementation detail that can be changed. However, it is guaranteed that "Done" will only be printed once the code in both withContext and launch completes.

If you need your coroutine to be confined to a particular thread or a thread-pool after resumption, but still want to execute it in the current call-frame until its first suspension, you can use an optional CoroutineStart parameter in coroutine builders like launch and async setting it to the value of CoroutineStart.UNDISPATCHED.