Skip to content

Clarify thread locals documentation #1016

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 1, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,11 @@ public interface ThreadContextElement<S> : 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<String?>()
* ...
Expand All @@ -97,7 +99,7 @@ public interface ThreadContextElement<S> : 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")
Expand All @@ -109,12 +111,27 @@ public interface ThreadContextElement<S> : 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 <T> ThreadLocal<T>.asContextElement(value: T = get()): ThreadContextElement<T> =
ThreadLocalElement(value, this)