@@ -67,7 +67,7 @@ You need to add a dependency on `kotlinx-coroutines-core` module as explained
67
67
* [ Parental responsibilities] ( #parental-responsibilities )
68
68
* [ Naming coroutines for debugging] ( #naming-coroutines-for-debugging )
69
69
* [ Cancellation via explicit job] ( #cancellation-via-explicit-job )
70
- * [ Thread-local data] ( #thread-local-data )
70
+ * [ Thread-local data] ( #thread-local-data )
71
71
* [ Channels] ( #channels )
72
72
* [ Channel basics] ( #channel-basics )
73
73
* [ Closing and iteration over channels] ( #closing-and-iteration-over-channels )
@@ -1262,36 +1262,36 @@ and cancel it when activity is destroyed. We cannot `join` them in the case of A
1262
1262
since it is synchronous, but this joining ability is useful when building backend services to ensure bounded
1263
1263
resource usage.
1264
1264
1265
- ## Thread-local data
1266
- Sometimes it's very convenient to have an ability to pass some thread-local data, but for coroutines, which
1267
- are not bound to any particular thread, it's hard to achieve it manually without writing a lot of boilerplate.
1265
+ ### Thread-local data
1266
+
1267
+ Sometimes it is very convenient to have an ability to pass some thread-local data, but, for coroutines, which
1268
+ are not bound to any particular thread, it is hard to achieve it manually without writing a lot of boilerplate.
1268
1269
1269
1270
For [ ` ThreadLocal ` ] ( https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html ) ,
1270
- [ asContextElement] is here for the rescue. It creates is an additional context element,
1271
- which remembers given ` ThreadLocal ` and restores it every time coroutine switches its context.
1271
+ [ asContextElement] is here for the rescue. It creates an additional context element,
1272
+ which keep the value of the given ` ThreadLocal ` and restores it every time the coroutine switches its context.
1272
1273
1273
- It's easy to demonstrate it in action:
1274
+ It is easy to demonstrate it in action:
1274
1275
1275
1276
<!-- - INCLUDE
1276
1277
import kotlin.coroutines.experimental.*
1277
1278
-->
1279
+
1278
1280
``` kotlin
1279
- val threadLocal = ThreadLocal <String ?>()
1281
+ val threadLocal = ThreadLocal <String ?>() // declare thread-local variable
1280
1282
1281
1283
fun main (args : Array <String >) = runBlocking<Unit > {
1282
1284
threadLocal.set(" main" )
1283
1285
println (" Pre-main, current thread: ${Thread .currentThread()} , thread local value: '${threadLocal.get()} '" )
1284
-
1285
- val job = launch(CommonPool + threadLocal.asContextElement(initialValue = " launch" ), start = CoroutineStart .UNDISPATCHED ) {
1286
+ val job = launch(CommonPool + threadLocal.asContextElement(value = " launch" ), start = CoroutineStart .UNDISPATCHED ) {
1286
1287
println (" Launch start, current thread: ${Thread .currentThread()} , thread local value: '${threadLocal.get()} '" )
1287
1288
yield ()
1288
1289
println (" After yield, current thread: ${Thread .currentThread()} , thread local value: '${threadLocal.get()} '" )
1289
1290
}
1290
-
1291
1291
job.join()
1292
1292
println (" Post-main, current thread: ${Thread .currentThread()} , thread local value: '${threadLocal.get()} '" )
1293
1293
}
1294
- ```
1294
+ ```
1295
1295
1296
1296
> You can get full code [ here] ( core/kotlinx-coroutines-core/test/guide/example-context-11.kt )
1297
1297
@@ -1304,17 +1304,21 @@ After yield, current thread: Thread[ForkJoinPool.commonPool-worker-1 @coroutine#
1304
1304
Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
1305
1305
```
1306
1306
1307
+ <!-- - TEST FLEXIBLE_THREAD -->
1307
1308
1308
- Note that thread-local is restored properly, no matter on what thread coroutine is executed.
1309
+ Note how thread-local value is restored properly, no matter on what thread the coroutine is executed.
1309
1310
` ThreadLocal ` has first-class support and can be used with any primitive ` kotlinx.corotuines ` provides.
1310
- It has the only limitation: if thread-local is mutated, a new value is not propagated to the coroutine caller
1311
- (as context element cannot track all ` ThreadLocal ` object accesses), but is properly propagated to newly launched coroutines .
1312
- To workaround it, value can be stored in a mutable box like ` class Counter(var i: Int) `
1311
+ It has one key limitation: when thread-local is mutated, a new value is not propagated to the coroutine caller
1312
+ (as context element cannot track all ` ThreadLocal ` object accesses) and updated value is lost on the next suspension .
1313
+ Use [ withContext ] to update the value of the thread-local in a coroutine, see [ asContextElement ] for more details.
1313
1314
1314
- For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries
1315
- which use thread-locals for passing data, [ ThreadContextElement] interface should be implemented.
1315
+ Alternatively, a value can be stored in a mutable box like ` class Counter(var i: Int) ` , which is, in turn,
1316
+ is stored in a thread-local variable. However, in this case you are fully responsible to synchronize
1317
+ potentially concurrent modifications to the variable in this box.
1316
1318
1317
- <!-- - TEST FLEXIBLE_THREAD -->
1319
+ For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries
1320
+ which internally use thread-locals for passing data, see documentation for [ ThreadContextElement] interface
1321
+ that should be implemented.
1318
1322
1319
1323
## Channels
1320
1324
0 commit comments