@@ -246,9 +246,15 @@ fun main() {
246246>
247247 {style="note"}
248248
249- It demonstrates several new techniques. One is using [ runBlocking] with an explicitly specified context, and
250- the other one is using the [ withContext] function to change the context of a coroutine while still staying in the
251- same coroutine, as you can see in the output below:
249+ The example above demonstrates new techniques in coroutine usage.
250+
251+ The first technique shows how to use [ runBlocking] with a specified context.
252+ The second technique involves calling [ withContext] ,
253+ which may suspend the current coroutine and switch to a new context—provided the new context differs from the existing one.
254+ Specifically, if you specify a different [ CoroutineDispatcher] , extra dispatches are required:
255+ the block is scheduled on the new dispatcher, and once it finishes, execution returns to the original dispatcher.
256+
257+ As a result, the output of the above code is:
252258
253259``` text
254260[Ctx1 @coroutine#1] Started in ctx1
@@ -258,8 +264,8 @@ same coroutine, as you can see in the output below:
258264
259265<!-- - TEST -->
260266
261- Note that this example also uses the ` use ` function from the Kotlin standard library to release threads
262- created with [ newSingleThreadContext] when they are no longer needed.
267+ The example above uses the ` use ` function from the Kotlin standard library
268+ to properly release thread resources created by [ newSingleThreadContext] when they're no longer needed.
263269
264270## Job in the context
265271
@@ -281,7 +287,7 @@ fun main() = runBlocking<Unit> {
281287>
282288 {style="note"}
283289
284- In the [ debug mode] ( #debugging-coroutines-and-threads ) , it outputs something like this:
290+ In [ debug mode] ( #debugging-coroutines-and-threads ) , it outputs something like this:
285291
286292```
287293My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
@@ -300,12 +306,12 @@ the [Job] of the new coroutine becomes
300306a _ child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
301307are recursively cancelled, too.
302308
303- However, this parent-child relation can be explicitly overriden in one of two ways:
309+ However, this parent-child relation can be explicitly overridden in one of two ways:
304310
3053111 . When a different scope is explicitly specified when launching a coroutine (for example, ` GlobalScope.launch ` ),
306- then it does not inherit a ` Job ` from the parent scope.
307- 2 . When a different ` Job ` object is passed as the context for the new coroutine (as shown in the example below),
308- then it overrides the ` Job ` of the parent scope.
312+ it does not inherit a ` Job ` from the parent scope.
313+ 2 . When a different ` Job ` object is passed as the context for the new coroutine (as shown in the example below),
314+ it overrides the ` Job ` of the parent scope.
309315
310316In both cases, the launched coroutine is not tied to the scope it was launched from and operates independently.
311317
@@ -356,7 +362,8 @@ job1: I am not affected by cancellation of the request
356362
357363## Parental responsibilities
358364
359- A parent coroutine always waits for completion of all its children. A parent does not have to explicitly track
365+ A parent coroutine always waits for the completion of all its children.
366+ A parent does not have to explicitly track
360367all the children it launches, and it does not have to use [ Job.join] to wait for them at the end:
361368
362369``` kotlin
@@ -480,11 +487,15 @@ I'm working in thread DefaultDispatcher-worker-1 @test#2
480487
481488## Coroutine scope
482489
483- Let us put our knowledge about contexts, children and jobs together. Assume that our application has
484- an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
485- and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
486- and update data, do animations, etc. All of these coroutines must be cancelled when the activity is destroyed
487- to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
490+ Let us put our knowledge about contexts, children, and jobs together.
491+ Assume that our application has an object with a lifecycle, but that object is not a coroutine.
492+ For example,
493+ we are writing an Android application,
494+ and launching various coroutines in the context of an Android activity
495+ to perform asynchronous operations to fetch and update data,
496+ do animations, etc. These coroutines must be cancelled when the activity is destroyed
497+ to avoid memory leaks.
498+ We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
488499and its coroutines, but ` kotlinx.coroutines ` provides an abstraction encapsulating that: [ CoroutineScope] .
489500You should be already familiar with the coroutine scope as all coroutine builders are declared as extensions on it.
490501
@@ -521,8 +532,9 @@ For the demo, we launch ten coroutines that delay for a different time:
521532```
522533
523534In our main function we create the activity, call our test ` doSomething ` function, and destroy the activity after 500ms.
524- This cancels all the coroutines that were launched from ` doSomething ` . We can see that because after the destruction
525- of the activity no more messages are printed, even if we wait a little longer.
535+ This cancels all the coroutines that were launched from ` doSomething ` .
536+ We can see that because after the destruction
537+ of the activity, no more messages are printed, even if we wait a little longer.
526538
527539<!-- - CLEAR -->
528540
@@ -577,16 +589,16 @@ Destroying activity!
577589<!-- - TEST -->
578590
579591As you can see, only the first two coroutines print a message and the others are cancelled
580- by a single invocation of ` job .cancel()` in ` Activity.destroy() ` .
592+ by a single invocation of [ ` mainScope .cancel()` ] [ CoroutineScope.cancel ] in ` Activity.destroy() ` .
581593
582- > Note, that Android has first-party support for coroutine scope in all entities with the lifecycle.
594+ > Note that Android has first-party support for coroutine scope in all entities with the lifecycle.
583595> See [ the corresponding documentation] ( https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope ) .
584596>
585597 {style="note"}
586598
587599### Thread-local data
588600
589- Sometimes it is convenient to have an ability to pass some thread-local data to or between coroutines.
601+ Sometimes it is convenient to be able to pass some thread-local data to or between coroutines.
590602However, since they are not bound to any particular thread, this will likely lead to boilerplate if done manually.
591603
592604For [ ` ThreadLocal ` ] ( https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html ) ,
@@ -620,8 +632,8 @@ fun main() = runBlocking<Unit> {
620632>
621633 {style="note"}
622634
623- In this example we launch a new coroutine in a background thread pool using [ Dispatchers.Default] , so
624- it works on a different thread from the thread pool, but it still has the value of the thread local variable
635+ In this example, we launch a new coroutine in a background thread pool using [ Dispatchers.Default] , so
636+ it works on different threads from the thread pool, but it still has the value of the thread local variable
625637that we specified using ` threadLocal.asContextElement(value = "launch") ` ,
626638no matter which thread the coroutine is executed on.
627639Thus, the output (with [ debug] ( #debugging-coroutines-and-threads ) ) is:
@@ -636,7 +648,7 @@ Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value:
636648<!-- - TEST FLEXIBLE_THREAD -->
637649
638650It's easy to forget to set the corresponding context element. The thread-local variable accessed from the coroutine may
639- then have an unexpected value, if the thread running the coroutine is different.
651+ then have an unexpected value if the thread running the coroutine is different.
640652To avoid such situations, it is recommended to use the [ ensurePresent] method
641653and fail-fast on improper usages.
642654
@@ -646,11 +658,12 @@ It has one key limitation, though: when a thread-local is mutated, a new value i
646658Use [ withContext] to update the value of the thread-local in a coroutine, see [ asContextElement] for more details.
647659
648660Alternatively, a value can be stored in a mutable box like ` class Counter(var i: Int) ` , which is, in turn,
649- stored in a thread-local variable. However, in this case you are fully responsible to synchronize
661+ stored in a thread-local variable.
662+ However, in this case, you are fully responsible to synchronize
650663potentially concurrent modifications to the variable in this mutable box.
651664
652- For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries
653- which internally use thread-locals for passing data, see the documentation of the [ ThreadContextElement] interface
665+ For advanced usage, for example, for integration with logging MDC, transactional contexts or any other libraries
666+ that internally use thread-locals for passing data, see the documentation of the [ ThreadContextElement] interface
654667that should be implemented.
655668
656669<!-- - MODULE kotlinx-coroutines-core -->
@@ -676,6 +689,7 @@ that should be implemented.
676689[ CoroutineScope() ] : https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
677690[ MainScope() ] : https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html
678691[ Dispatchers.Main ] : https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
692+ [ CoroutineScope.cancel ] : https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel.html
679693[ asContextElement ] : https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-context-element.html
680694[ ensurePresent ] : https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-present.html
681695[ ThreadContextElement ] : https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html
0 commit comments