Kotlin Coroutines builders & scope

🧩 Builders

Builder Returns Blocks OS thread Waits completion New Job Root Job New coroutine Root coroutine Suspend

point

runBlocking { }
(plug, rarely used)
block result ✓ Yes ✓ Yes ✓ Yes ✓ Yes ✓ Yes ✓ Yes CEH doesn't work ✗ No
withContext(Dispatcher...) { }
| runInterruptible { }
block result ✗ No ✓ Yes ✗ No ✗ No ✓ Yes
coroutineScope { } block result ✗ No ✓ Yes ✓ Yes ✗ No ✓ Yes ✗ No ✓ Yes
supervisorScope { } block result ✗ No ✓ Yes ✓ Yes SupervisorJob ✗ No ✓ Yes ✗ No CEH works
for children
✓ Yes
GlobalScope. ... { }
(e.g., GlobalScope.launch { })
Job/Deffered ✗ No ✗ No ✓ Yes ✓ Yes ✓ Yes ✓ Yes ✗ No
launch { } / async { } Job/Deffered ✗ No ✗ No ✓ Yes ✗ No ✓ Yes ✗ No ✗ No
launch(Job()) { } / async(Job()) { } ⚠️ anti-pattern breaks structured concurrency
Job/Deffered ✗ No ✗ No ✓ Yes ✓ Yes ✓ Yes ✓ Yes passed Job() becomes root CEH works for launch,
NOT for async
✗ No

🧩 Scope constructor

Expression Returns Blocks thread Waits completion New Job Root Job New coroutine Root coroutine Suspend

point

val my = CoroutineScope()
| CoroutineScope(Job())
| CoroutineScope(SupervisorJob())
itself ✗ No ✗ No ✓ Yes ✓ Yes gets/creates root ✗ No ✗ No
Coroutine is a code block that:
CEH (CoroutineExceptionHandler) — is a last hope mechanism. CEH works only for root coroutine, because unhandled exception of not-root coroutines spreads up the hierarcy in structured concurrency and CEH is ignored. Exceptions to this rule are marked in the table above.
SupervisorJob defines a rule for child coroutines: failure of any one of them is isolated – it does not cancel the others in the same scope (including the parent). So, its exception is only its problem, that's why CEH works for them.