Skip to content

Commit 0b91810

Browse files
committed
Clarify thread locals documentation
Fixes #985
1 parent b37c296 commit 0b91810

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt

+20-3
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,11 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
8181
* Wraps [ThreadLocal] into [ThreadContextElement]. The resulting [ThreadContextElement]
8282
* maintains the given [value] of the given [ThreadLocal] for coroutine regardless of the actual thread its is resumed on.
8383
* By default [ThreadLocal.get] is used as a value for the thread-local variable, but it can be overridden with [value] parameter.
84+
* Beware that context element **does not track** modifications of the thread-local and accessing thread-local from coroutine
85+
* without corresponding context element returns **undefined** value. See the examples for a detailed description.
8486
*
85-
* Example usage looks like this:
8687
*
88+
* Example usage:
8789
* ```
8890
* val myThreadLocal = ThreadLocal<String?>()
8991
* ...
@@ -97,7 +99,7 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
9799
* println(myThreadLocal.get()) // Prints "null"
98100
* ```
99101
*
100-
* Note that the context element does not track modifications of the thread-local variable, for example:
102+
* The context element does not track modifications of the thread-local variable, for example:
101103
*
102104
* ```
103105
* myThreadLocal.set("main")
@@ -109,12 +111,27 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
109111
* ```
110112
*
111113
* Use `withContext` to update the corresponding thread-local variable to a different value, for example:
112-
*
113114
* ```
114115
* withContext(myThreadLocal.asContextElement("foo")) {
115116
* println(myThreadLocal.get()) // Prints "foo"
116117
* }
117118
* ```
119+
*
120+
* Accessing thread-local without corresponding context element leads to undefined value:
121+
* ```
122+
* val tl = ThreadLocal.withInitial { "initial" }
123+
*
124+
* runBlocking {
125+
* println(tl.get()) // Will print "initial"
126+
* // Change context
127+
* withContext(tl.asContextElement("modified")) {
128+
* println(tl.get()) // Will print "modified"
129+
* }
130+
* // Context is changed again
131+
* println(tl.get()) // <- WARN: can print either "modified" or "initial"
132+
* }
133+
* ```
134+
* to fix this behaviour use `runBlocking(tl.asContextElement())`
118135
*/
119136
public fun <T> ThreadLocal<T>.asContextElement(value: T = get()): ThreadContextElement<T> =
120137
ThreadLocalElement(value, this)

0 commit comments

Comments
 (0)