A coroutine dispatcher decides which thread or threads execute a coroutine. Coroutines are not permanently tied to one thread: after suspension, a dispatcher may resume them on another. This makes thread choice an explicit design decision rather than an accidental property of sequential-looking suspend code. section 14.7 section 14.9
Choose a dispatcher when the work has a reason to run somewhere particular. Dispatchers.Default is the general-purpose choice for CPU-bound work and uses a pool sized to available CPU cores. Dispatchers.Main targets the UI thread supplied by a UI framework. Dispatchers.IO offloads work that calls blocking APIs. For ordinary work without a UI, blocking-IO, or confinement requirement, Default is the usual choice. section 14.7.1
Table 14.2 Dispatchers available out of the box in Kotlin coroutines (view table figure)
Compare the built-in dispatcher choices by thread count and intended workload, including Default, Main, IO, Unconfined, and limitedParallelism(n). section 14.7.1
Start background work on Default
Pass a dispatcher to a coroutine builder: `launch(Dispatchers.Default) { log("Doing some background work") }`. The surrounding `runBlocking` code logs on the main thread, while the launched coroutine logs from a Default dispatcher worker thread. Builders such as `runBlocking`, `launch`, and `async` all accept this context argument. section 14.7.2
A child coroutine normally inherits its parent’s dispatcher, so every builder call does not need an explicit choice. To move only a portion of an existing coroutine, use `withContext` instead. A common UI pattern performs a long-running operation on Default, then uses `withContext(Dispatchers.Main)` to update the interface. Main requires a configured UI framework; switching to IO does not. section 14.7.1 section 14.7.3
Dispatcher selection does not remove concurrency responsibilities:
- One coroutine executes sequentially, even if its dispatcher may run it on different threads over time. section 14.7.4
- Multiple coroutines on a multithreaded dispatcher can modify shared state in parallel and lose updates. section 14.7.4
- Protect shared critical sections with a Mutex or suitable atomic or thread-safe data structure; single-thread confinement can also avoid the race. section 14.7.4
A dispatcher is one element of a CoroutineContext, alongside lifecycle information such as a Job and optional metadata such as CoroutineName or CoroutineExceptionHandler. Passing context to a builder or `withContext` replaces the corresponding context element; combine several context elements with `+` when both a dispatcher and metadata are needed. section 14.8
