diff --git a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt index 68098f3829..f83ced2caa 100644 --- a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt +++ b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt @@ -81,9 +81,11 @@ public interface ThreadContextElement : CoroutineContext.Element { * Wraps [ThreadLocal] into [ThreadContextElement]. The resulting [ThreadContextElement] * maintains the given [value] of the given [ThreadLocal] for coroutine regardless of the actual thread its is resumed on. * By default [ThreadLocal.get] is used as a value for the thread-local variable, but it can be overridden with [value] parameter. + * Beware that context element **does not track** modifications of the thread-local and accessing thread-local from coroutine + * without the corresponding context element returns **undefined** value. See the examples for a detailed description. * - * Example usage looks like this: * + * Example usage: * ``` * val myThreadLocal = ThreadLocal() * ... @@ -97,7 +99,7 @@ public interface ThreadContextElement : CoroutineContext.Element { * println(myThreadLocal.get()) // Prints "null" * ``` * - * Note that the context element does not track modifications of the thread-local variable, for example: + * The context element does not track modifications of the thread-local variable, for example: * * ``` * myThreadLocal.set("main") @@ -109,12 +111,27 @@ public interface ThreadContextElement : CoroutineContext.Element { * ``` * * Use `withContext` to update the corresponding thread-local variable to a different value, for example: - * * ``` * withContext(myThreadLocal.asContextElement("foo")) { * println(myThreadLocal.get()) // Prints "foo" * } * ``` + * + * Accessing the thread-local without corresponding context element leads to undefined value: + * ``` + * val tl = ThreadLocal.withInitial { "initial" } + * + * runBlocking { + * println(tl.get()) // Will print "initial" + * // Change context + * withContext(tl.asContextElement("modified")) { + * println(tl.get()) // Will print "modified" + * } + * // Context is changed again + * println(tl.get()) // <- WARN: can print either "modified" or "initial" + * } + * ``` + * to fix this behaviour use `runBlocking(tl.asContextElement())` */ public fun ThreadLocal.asContextElement(value: T = get()): ThreadContextElement = ThreadLocalElement(value, this)