liveBook · Manning

Coroutine context

As explained in Kotlin in Action, 2E

coroutineContext is a compiler-provided property that exposes the context of the currently executing coroutine from a suspending function.

`coroutineContext` is a compiler-provided property available inside a suspending function. It exposes the `CoroutineContext` of the coroutine currently running that function. Think of that context as a set of elements describing how the coroutine runs and how it participates in its lifetime: commonly a dispatcher and a `Job`, plus optional elements such as `CoroutineName` and `CoroutineExceptionHandler`. section 14.8

import kotlin.coroutines.coroutineContext
 
suspend fun introspect() {
    log(coroutineContext)    #1
}
 
fun main() {
    runBlocking {
        introspect()
    }
}
 
// 25 [main @coroutine#1] [CoroutineId(1),
    "coroutine#1":BlockingCoroutine{Active}@610694f1,
    BlockingEventLoop@43814d18]

Read `coroutineContext` directly from a suspending function when inspecting the active coroutine. The logged value reveals its installed context elements. section 14.8

A dispatcher argument passed to `runBlocking`, `launch`, `async`, or `withContext` is really a `CoroutineContext` argument. Supplying an element replaces that element in the child context; combine several elements with `+`. This lets one call set both execution policy and useful metadata. section 14.8 section 14.9

Override selected context elements

```kotlin fun main() { runBlocking(Dispatchers.IO + CoroutineName("Coolroutine")) { introspect() } } ``` Here `Dispatchers.IO` replaces the dispatcher otherwise used by `runBlocking`, while `CoroutineName("Coolroutine")` adds a name. Other inherited elements remain available unless replaced by another element with the same role. section 14.8

Contexts follow the structured-concurrency hierarchy. A newly started child first inherits its parent context, then receives a new `Job` linked to the parent job, and finally applies any context arguments supplied at creation. Consequently, a `launch` without a dispatcher does not automatically use `Dispatchers.Default`; it uses the parent dispatcher. section 15.1.4

fun main() {
   runBlocking(Dispatchers.Default) {
       log(coroutineContext)
       launch {
           log(coroutineContext)
           launch(Dispatchers.IO + CoroutineName("mine")) {
               log(coroutineContext)
           }
       }
   }
}

// 0 [DefaultDispatcher-worker-1 @coroutine#1] [CoroutineId(1),
   "coroutine#1":BlockingCoroutine{Active}@68308697, Dispatchers.Default]
// 1 [DefaultDispatcher-worker-2 @coroutine#2] [CoroutineId(2),
   "coroutine#2":StandaloneCoroutine{Active}@2b3ce773, Dispatchers.Default]
// 2 [DefaultDispatcher-worker-3 @mine#3] [CoroutineName(mine),
   CoroutineId(3), "mine#3":StandaloneCoroutine{Active}@7c42841a,
   Dispatchers.IO]

Compare the logged contexts: the first child inherits `Dispatchers.Default`, while the nested child overrides that dispatcher with `Dispatchers.IO` and receives its own name. section 15.1.4

Use `coroutineContext` to reason about these practical concerns:

  • Inspect the current `Job`, including its `parent` and `children`, to make the coroutine hierarchy visible. section 15.1.4
  • Understand cancellation boundaries: the `Job` in the context establishes the parent-child relationship used by structured concurrency. section 15.3
  • Attach a `CoroutineExceptionHandler` to customize last-resort processing of uncaught exceptions at a root coroutine. section 18.3 section 18.6

A context is not merely a thread choice. It combines execution information, lifecycle structure, names, and optional failure handling. Inspect it from suspending code, inherit it deliberately through coroutine hierarchies, and override only the elements a child genuinely needs. section 14.8 section 15.1.4

How Kotlin in Action, 2E covers it

How deep it goes
Defines context elements and overrides, then traces inheritance and Job relationships through nested coroutine hierarchies.
Examples
Uses context logging, `runBlocking` with `Dispatchers.IO` and `CoroutineName`, nested `launch`, and Job parent-child inspection.
What it assumes
Assumes suspending functions and coroutine builders, then explains coroutine-context elements and inheritance from zero.
What you can do after
Evaluate/understand which context elements a coroutine inherits, replaces, and exposes while it executes.
How it connects
Connects CoroutineDispatcher, Job, structured concurrency, CoroutineName, CoroutineExceptionHandler, cancellation, and coroutineScope.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.