1<!--- TEST_NAME DispatcherGuideTest -->
2
3**Table of contents**
4
5<!--- TOC -->
6
7* [Coroutine Context and Dispatchers](#coroutine-context-and-dispatchers)
8  * [Dispatchers and threads](#dispatchers-and-threads)
9  * [Unconfined vs confined dispatcher](#unconfined-vs-confined-dispatcher)
10  * [Debugging coroutines and threads](#debugging-coroutines-and-threads)
11    * [Debugging with IDEA](#debugging-with-idea)
12    * [Debugging using logging](#debugging-using-logging)
13  * [Jumping between threads](#jumping-between-threads)
14  * [Job in the context](#job-in-the-context)
15  * [Children of a coroutine](#children-of-a-coroutine)
16  * [Parental responsibilities](#parental-responsibilities)
17  * [Naming coroutines for debugging](#naming-coroutines-for-debugging)
18  * [Combining context elements](#combining-context-elements)
19  * [Coroutine scope](#coroutine-scope)
20  * [Thread-local data](#thread-local-data)
21
22<!--- END -->
23
24## Coroutine Context and Dispatchers
25
26Coroutines always execute in some context represented by a value of the
27[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/)
28type, defined in the Kotlin standard library.
29
30The coroutine context is a set of various elements. The main elements are the [Job] of the coroutine,
31which we've seen before, and its dispatcher, which is covered in this section.
32
33### Dispatchers and threads
34
35The coroutine context includes a _coroutine dispatcher_ (see [CoroutineDispatcher]) that determines what thread or threads
36the corresponding coroutine uses for its execution. The coroutine dispatcher can confine coroutine execution
37to a specific thread, dispatch it to a thread pool, or let it run unconfined.
38
39All coroutine builders like [launch] and [async] accept an optional
40[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/)
41parameter that can be used to explicitly specify the dispatcher for the new coroutine and other context elements.
42
43Try the following example:
44
45<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
46
47```kotlin
48import kotlinx.coroutines.*
49
50fun main() = runBlocking<Unit> {
51//sampleStart
52    launch { // context of the parent, main runBlocking coroutine
53        println("main runBlocking      : I'm working in thread ${Thread.currentThread().name}")
54    }
55    launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
56        println("Unconfined            : I'm working in thread ${Thread.currentThread().name}")
57    }
58    launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher
59        println("Default               : I'm working in thread ${Thread.currentThread().name}")
60    }
61    launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
62        println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
63    }
64//sampleEnd
65}
66```
67
68</div>
69
70> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-01.kt).
71
72It produces the following output (maybe in different order):
73
74```text
75Unconfined            : I'm working in thread main
76Default               : I'm working in thread DefaultDispatcher-worker-1
77newSingleThreadContext: I'm working in thread MyOwnThread
78main runBlocking      : I'm working in thread main
79```
80
81<!--- TEST LINES_START_UNORDERED -->
82
83When `launch { ... }` is used without parameters, it inherits the context (and thus dispatcher)
84from the [CoroutineScope] it is being launched from. In this case, it inherits the
85context of the main `runBlocking` coroutine which runs in the `main` thread.
86
87[Dispatchers.Unconfined] is a special dispatcher that also appears to run in the `main` thread, but it is,
88in fact, a different mechanism that is explained later.
89
90The default dispatcher that is used when coroutines are launched in [GlobalScope]
91is represented by [Dispatchers.Default] and uses a shared background pool of threads,
92so `launch(Dispatchers.Default) { ... }` uses the same dispatcher as `GlobalScope.launch { ... }`.
93
94[newSingleThreadContext] creates a thread for the coroutine to run.
95A dedicated thread is a very expensive resource.
96In a real application it must be either released, when no longer needed, using the [close][ExecutorCoroutineDispatcher.close]
97function, or stored in a top-level variable and reused throughout the application.
98
99### Unconfined vs confined dispatcher
100
101The [Dispatchers.Unconfined] coroutine dispatcher starts a coroutine in the caller thread, but only until the
102first suspension point. After suspension it resumes the coroutine in the thread that is fully determined by the
103suspending function that was invoked. The unconfined dispatcher is appropriate for coroutines which neither
104consume CPU time nor update any shared data (like UI) confined to a specific thread.
105
106On the other side, the dispatcher is inherited from the outer [CoroutineScope] by default.
107The default dispatcher for the [runBlocking] coroutine, in particular,
108is confined to the invoker thread, so inheriting it has the effect of confining execution to
109this thread with predictable FIFO scheduling.
110
111<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
112
113```kotlin
114import kotlinx.coroutines.*
115
116fun main() = runBlocking<Unit> {
117//sampleStart
118    launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
119        println("Unconfined      : I'm working in thread ${Thread.currentThread().name}")
120        delay(500)
121        println("Unconfined      : After delay in thread ${Thread.currentThread().name}")
122    }
123    launch { // context of the parent, main runBlocking coroutine
124        println("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
125        delay(1000)
126        println("main runBlocking: After delay in thread ${Thread.currentThread().name}")
127    }
128//sampleEnd
129}
130```
131
132</div>
133
134> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-02.kt).
135
136Produces the output:
137
138```text
139Unconfined      : I'm working in thread main
140main runBlocking: I'm working in thread main
141Unconfined      : After delay in thread kotlinx.coroutines.DefaultExecutor
142main runBlocking: After delay in thread main
143```
144
145<!--- TEST LINES_START -->
146
147So, the coroutine with the context inherited from `runBlocking {...}` continues to execute
148in the `main` thread, while the unconfined one resumes in the default executor thread that the [delay]
149function is using.
150
151> The unconfined dispatcher is an advanced mechanism that can be helpful in certain corner cases where
152dispatching of a coroutine for its execution later is not needed or produces undesirable side-effects,
153because some operation in a coroutine must be performed right away.
154The unconfined dispatcher should not be used in general code.
155
156### Debugging coroutines and threads
157
158Coroutines can suspend on one thread and resume on another thread.
159Even with a single-threaded dispatcher it might be hard to
160figure out what the coroutine was doing, where, and when if you don't have special tooling.
161
162#### Debugging with IDEA
163
164The Coroutine Debugger of the Kotlin plugin simplifies debugging coroutines in IntelliJ IDEA.
165
166> Debugging works for versions 1.3.8 or later of `kotlinx-coroutines-core`.
167
168The **Debug** tool window contains the **Coroutines** tab. In this tab, you can find information about both currently running and suspended coroutines.
169The coroutines are grouped by the dispatcher they are running on.
170
171![Debugging coroutines](images/coroutine-idea-debugging-1.png)
172
173With the coroutine debugger, you can:
174* Check the state of each coroutine.
175* See the values of local and captured variables for both running and suspended coroutines.
176* See a full coroutine creation stack, as well as a call stack inside the coroutine. The stack includes all frames with
177variable values, even those that would be lost during standard debugging.
178* Get a full report that contains the state of each coroutine and its stack. To obtain it, right-click inside the **Coroutines** tab, and then click **Get Coroutines Dump**.
179
180To start coroutine debugging, you just need to set breakpoints and run the application in debug mode.
181
182Learn more about coroutines debugging in the [tutorial](https://kotlinlang.org/docs/tutorials/coroutines/debug-coroutines-with-idea.html).
183
184#### Debugging using logging
185
186Another approach to debugging applications with
187threads without Coroutine Debugger is to print the thread name in the log file on each log statement. This feature is universally supported
188by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so
189`kotlinx.coroutines` includes debugging facilities to make it easier.
190
191Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
192
193<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
194
195```kotlin
196import kotlinx.coroutines.*
197
198fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
199
200fun main() = runBlocking<Unit> {
201//sampleStart
202    val a = async {
203        log("I'm computing a piece of the answer")
204        6
205    }
206    val b = async {
207        log("I'm computing another piece of the answer")
208        7
209    }
210    log("The answer is ${a.await() * b.await()}")
211//sampleEnd
212}
213```
214
215</div>
216
217> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-03.kt).
218
219There are three coroutines. The main coroutine (#1) inside `runBlocking`
220and two coroutines computing the deferred values `a` (#2) and `b` (#3).
221They are all executing in the context of `runBlocking` and are confined to the main thread.
222The output of this code is:
223
224```text
225[main @coroutine#2] I'm computing a piece of the answer
226[main @coroutine#3] I'm computing another piece of the answer
227[main @coroutine#1] The answer is 42
228```
229
230<!--- TEST FLEXIBLE_THREAD -->
231
232The `log` function prints the name of the thread in square brackets, and you can see that it is the `main`
233thread with the identifier of the currently executing coroutine appended to it. This identifier
234is consecutively assigned to all created coroutines when the debugging mode is on.
235
236> Debugging mode is also turned on when JVM is run with `-ea` option.
237You can read more about debugging facilities in the documentation of the [DEBUG_PROPERTY_NAME] property.
238
239### Jumping between threads
240
241Run the following code with the `-Dkotlinx.coroutines.debug` JVM option (see [debug](#debugging-coroutines-and-threads)):
242
243<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
244
245```kotlin
246import kotlinx.coroutines.*
247
248fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
249
250fun main() {
251//sampleStart
252    newSingleThreadContext("Ctx1").use { ctx1 ->
253        newSingleThreadContext("Ctx2").use { ctx2 ->
254            runBlocking(ctx1) {
255                log("Started in ctx1")
256                withContext(ctx2) {
257                    log("Working in ctx2")
258                }
259                log("Back to ctx1")
260            }
261        }
262    }
263//sampleEnd
264}
265```
266
267</div>
268
269> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-04.kt).
270
271It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
272the other one is using the [withContext] function to change the context of a coroutine while still staying in the
273same coroutine, as you can see in the output below:
274
275```text
276[Ctx1 @coroutine#1] Started in ctx1
277[Ctx2 @coroutine#1] Working in ctx2
278[Ctx1 @coroutine#1] Back to ctx1
279```
280
281<!--- TEST -->
282
283Note that this example also uses the `use` function from the Kotlin standard library to release threads
284created with [newSingleThreadContext] when they are no longer needed.
285
286### Job in the context
287
288The coroutine's [Job] is part of its context, and can be retrieved from it
289using the `coroutineContext[Job]` expression:
290
291<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
292
293```kotlin
294import kotlinx.coroutines.*
295
296fun main() = runBlocking<Unit> {
297//sampleStart
298    println("My job is ${coroutineContext[Job]}")
299//sampleEnd
300}
301```
302
303</div>
304
305> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-05.kt).
306
307In the [debug mode](#debugging-coroutines-and-threads), it outputs something like this:
308
309```
310My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
311```
312
313<!--- TEST lines.size == 1 && lines[0].startsWith("My job is \"coroutine#1\":BlockingCoroutine{Active}@") -->
314
315Note that [isActive] in [CoroutineScope] is just a convenient shortcut for
316`coroutineContext[Job]?.isActive == true`.
317
318### Children of a coroutine
319
320When a coroutine is launched in the [CoroutineScope] of another coroutine,
321it inherits its context via [CoroutineScope.coroutineContext] and
322the [Job] of the new coroutine becomes
323a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
324are recursively cancelled, too.
325
326However, when [GlobalScope] is used to launch a coroutine, there is no parent for the job of the new coroutine.
327It is therefore not tied to the scope it was launched from and operates independently.
328
329
330<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
331
332```kotlin
333import kotlinx.coroutines.*
334
335fun main() = runBlocking<Unit> {
336//sampleStart
337    // launch a coroutine to process some kind of incoming request
338    val request = launch {
339        // it spawns two other jobs, one with GlobalScope
340        GlobalScope.launch {
341            println("job1: I run in GlobalScope and execute independently!")
342            delay(1000)
343            println("job1: I am not affected by cancellation of the request")
344        }
345        // and the other inherits the parent context
346        launch {
347            delay(100)
348            println("job2: I am a child of the request coroutine")
349            delay(1000)
350            println("job2: I will not execute this line if my parent request is cancelled")
351        }
352    }
353    delay(500)
354    request.cancel() // cancel processing of the request
355    delay(1000) // delay a second to see what happens
356    println("main: Who has survived request cancellation?")
357//sampleEnd
358}
359```
360
361</div>
362
363> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-06.kt).
364
365The output of this code is:
366
367```text
368job1: I run in GlobalScope and execute independently!
369job2: I am a child of the request coroutine
370job1: I am not affected by cancellation of the request
371main: Who has survived request cancellation?
372```
373
374<!--- TEST -->
375
376### Parental responsibilities
377
378A parent coroutine always waits for completion of all its children. A parent does not have to explicitly track
379all the children it launches, and it does not have to use [Job.join] to wait for them at the end:
380
381<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
382
383```kotlin
384import kotlinx.coroutines.*
385
386fun main() = runBlocking<Unit> {
387//sampleStart
388    // launch a coroutine to process some kind of incoming request
389    val request = launch {
390        repeat(3) { i -> // launch a few children jobs
391            launch  {
392                delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
393                println("Coroutine $i is done")
394            }
395        }
396        println("request: I'm done and I don't explicitly join my children that are still active")
397    }
398    request.join() // wait for completion of the request, including all its children
399    println("Now processing of the request is complete")
400//sampleEnd
401}
402```
403
404</div>
405
406> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-07.kt).
407
408The result is going to be:
409
410```text
411request: I'm done and I don't explicitly join my children that are still active
412Coroutine 0 is done
413Coroutine 1 is done
414Coroutine 2 is done
415Now processing of the request is complete
416```
417
418<!--- TEST -->
419
420### Naming coroutines for debugging
421
422Automatically assigned ids are good when coroutines log often and you just need to correlate log records
423coming from the same coroutine. However, when a coroutine is tied to the processing of a specific request
424or doing some specific background task, it is better to name it explicitly for debugging purposes.
425The [CoroutineName] context element serves the same purpose as the thread name. It is included in the thread name that
426is executing this coroutine when the [debugging mode](#debugging-coroutines-and-threads) is turned on.
427
428The following example demonstrates this concept:
429
430<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
431
432```kotlin
433import kotlinx.coroutines.*
434
435fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
436
437fun main() = runBlocking(CoroutineName("main")) {
438//sampleStart
439    log("Started main coroutine")
440    // run two background value computations
441    val v1 = async(CoroutineName("v1coroutine")) {
442        delay(500)
443        log("Computing v1")
444        252
445    }
446    val v2 = async(CoroutineName("v2coroutine")) {
447        delay(1000)
448        log("Computing v2")
449        6
450    }
451    log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
452//sampleEnd
453}
454```
455
456</div>
457
458> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-08.kt).
459
460The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar to:
461
462```text
463[main @main#1] Started main coroutine
464[main @v1coroutine#2] Computing v1
465[main @v2coroutine#3] Computing v2
466[main @main#1] The answer for v1 / v2 = 42
467```
468
469<!--- TEST FLEXIBLE_THREAD -->
470
471### Combining context elements
472
473Sometimes we need to define multiple elements for a coroutine context. We can use the `+` operator for that.
474For example, we can launch a coroutine with an explicitly specified dispatcher and an explicitly specified
475name at the same time:
476
477<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
478
479```kotlin
480import kotlinx.coroutines.*
481
482fun main() = runBlocking<Unit> {
483//sampleStart
484    launch(Dispatchers.Default + CoroutineName("test")) {
485        println("I'm working in thread ${Thread.currentThread().name}")
486    }
487//sampleEnd
488}
489```
490
491</div>
492
493> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-09.kt).
494
495The output of this code with the `-Dkotlinx.coroutines.debug` JVM option is:
496
497```text
498I'm working in thread DefaultDispatcher-worker-1 @test#2
499```
500
501<!--- TEST FLEXIBLE_THREAD -->
502
503### Coroutine scope
504
505Let us put our knowledge about contexts, children and jobs together. Assume that our application has
506an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
507and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
508and update data, do animations, etc. All of these coroutines must be cancelled when the activity is destroyed
509to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
510and its coroutines, but `kotlinx.coroutines` provides an abstraction encapsulating that: [CoroutineScope].
511You should be already familiar with the coroutine scope as all coroutine builders are declared as extensions on it.
512
513We manage the lifecycles of our coroutines by creating an instance of [CoroutineScope] tied to
514the lifecycle of our activity. A `CoroutineScope` instance can be created by the [CoroutineScope()] or [MainScope()]
515factory functions. The former creates a general-purpose scope, while the latter creates a scope for UI applications and uses
516[Dispatchers.Main] as the default dispatcher:
517
518<div class="sample" markdown="1" theme="idea" data-highlight-only>
519
520```kotlin
521class Activity {
522    private val mainScope = MainScope()
523
524    fun destroy() {
525        mainScope.cancel()
526    }
527    // to be continued ...
528```
529
530</div>
531
532Now, we can launch coroutines in the scope of this `Activity` using the defined `scope`.
533For the demo, we launch ten coroutines that delay for a different time:
534
535<div class="sample" markdown="1" theme="idea" data-highlight-only>
536
537```kotlin
538    // class Activity continues
539    fun doSomething() {
540        // launch ten coroutines for a demo, each working for a different time
541        repeat(10) { i ->
542            mainScope.launch {
543                delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
544                println("Coroutine $i is done")
545            }
546        }
547    }
548} // class Activity ends
549```
550
551</div>
552
553In our main function we create the activity, call our test `doSomething` function, and destroy the activity after 500ms.
554This cancels all the coroutines that were launched from `doSomething`. We can see that because after the destruction
555of the activity no more messages are printed, even if we wait a little longer.
556
557<!--- CLEAR -->
558
559<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
560
561```kotlin
562import kotlinx.coroutines.*
563
564class Activity {
565    private val mainScope = CoroutineScope(Dispatchers.Default) // use Default for test purposes
566
567    fun destroy() {
568        mainScope.cancel()
569    }
570
571    fun doSomething() {
572        // launch ten coroutines for a demo, each working for a different time
573        repeat(10) { i ->
574            mainScope.launch {
575                delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
576                println("Coroutine $i is done")
577            }
578        }
579    }
580} // class Activity ends
581
582fun main() = runBlocking<Unit> {
583//sampleStart
584    val activity = Activity()
585    activity.doSomething() // run test function
586    println("Launched coroutines")
587    delay(500L) // delay for half a second
588    println("Destroying activity!")
589    activity.destroy() // cancels all coroutines
590    delay(1000) // visually confirm that they don't work
591//sampleEnd
592}
593```
594
595</div>
596
597> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-10.kt).
598
599The output of this example is:
600
601```text
602Launched coroutines
603Coroutine 0 is done
604Coroutine 1 is done
605Destroying activity!
606```
607
608<!--- TEST -->
609
610As you can see, only the first two coroutines print a message and the others are cancelled
611by a single invocation of `job.cancel()` in `Activity.destroy()`.
612
613> Note, that Android has first-party support for coroutine scope in all entities with the lifecycle.
614See [the corresponding documentation](https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope).
615
616### Thread-local data
617
618Sometimes it is convenient to have an ability to pass some thread-local data to or between coroutines.
619However, since they are not bound to any particular thread, this will likely lead to boilerplate if done manually.
620
621For [`ThreadLocal`](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html),
622the [asContextElement] extension function is here for the rescue. It creates an additional context element
623which keeps the value of the given `ThreadLocal` and restores it every time the coroutine switches its context.
624
625It is easy to demonstrate it in action:
626
627<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
628
629```kotlin
630import kotlinx.coroutines.*
631
632val threadLocal = ThreadLocal<String?>() // declare thread-local variable
633
634fun main() = runBlocking<Unit> {
635//sampleStart
636    threadLocal.set("main")
637    println("Pre-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
638    val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = "launch")) {
639        println("Launch start, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
640        yield()
641        println("After yield, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
642    }
643    job.join()
644    println("Post-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
645//sampleEnd
646}
647```
648
649</div>
650
651> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-11.kt).
652
653In this example we launch a new coroutine in a background thread pool using [Dispatchers.Default], so
654it works on a different thread from the thread pool, but it still has the value of the thread local variable
655that we specified using `threadLocal.asContextElement(value = "launch")`,
656no matter which thread the coroutine is executed on.
657Thus, the output (with [debug](#debugging-coroutines-and-threads)) is:
658
659```text
660Pre-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
661Launch start, current thread: Thread[DefaultDispatcher-worker-1 @coroutine#2,5,main], thread local value: 'launch'
662After yield, current thread: Thread[DefaultDispatcher-worker-2 @coroutine#2,5,main], thread local value: 'launch'
663Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
664```
665
666<!--- TEST FLEXIBLE_THREAD -->
667
668It's easy to forget to set the corresponding context element. The thread-local variable accessed from the coroutine may
669then have an unexpected value, if the thread running the coroutine is different.
670To avoid such situations, it is recommended to use the [ensurePresent] method
671and fail-fast on improper usages.
672
673`ThreadLocal` has first-class support and can be used with any primitive `kotlinx.coroutines` provides.
674It has one key limitation, though: when a thread-local is mutated, a new value is not propagated to the coroutine caller
675(because a context element cannot track all `ThreadLocal` object accesses), and the updated value is lost on the next suspension.
676Use [withContext] to update the value of the thread-local in a coroutine, see [asContextElement] for more details.
677
678Alternatively, a value can be stored in a mutable box like `class Counter(var i: Int)`, which is, in turn,
679stored in a thread-local variable. However, in this case you are fully responsible to synchronize
680potentially concurrent modifications to the variable in this mutable box.
681
682For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries
683which internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface
684that should be implemented.
685
686<!--- MODULE kotlinx-coroutines-core -->
687<!--- INDEX kotlinx.coroutines -->
688[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
689[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
690[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
691[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
692[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
693[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html
694[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
695[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
696[newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-single-thread-context.html
697[ExecutorCoroutineDispatcher.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-executor-coroutine-dispatcher/close.html
698[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
699[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
700[DEBUG_PROPERTY_NAME]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-d-e-b-u-g_-p-r-o-p-e-r-t-y_-n-a-m-e.html
701[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
702[isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html
703[CoroutineScope.coroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html
704[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
705[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
706[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
707[MainScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html
708[Dispatchers.Main]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
709[asContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.lang.-thread-local/as-context-element.html
710[ensurePresent]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.lang.-thread-local/ensure-present.html
711[ThreadContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html
712<!--- END -->
713