analog coroutine để ThreadLocal
là CoroutineContext
.
Để tương thích với ThreadLocal
-sử dụng thư viện bạn cần triển khai ContinuationInterceptor
tùy chỉnh có hỗ trợ các chỉ đường cục bộ cụ thể theo khung.
Đây là một ví dụ. Chúng ta hãy giả sử rằng chúng ta sử dụng một số khuôn khổ dựa trên một cụ ThreadLocal
để lưu trữ một số dữ liệu ứng dụng cụ thể (MyData
trong ví dụ này):
val myThreadLocal = ThreadLocal<MyData>()
Để sử dụng nó với coroutines, bạn sẽ cần phải thực hiện một bối cảnh mà giữ giá trị hiện tại của MyData
và đặt nó vào tương ứng ThreadLocal
mỗi khi coroutine được nối lại trên một sợi. Mã nên trông như thế này:
class MyContext(
private var myData: MyData,
private val dispatcher: ContinuationInterceptor
) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
dispatcher.interceptContinuation(Wrapper(continuation))
inner class Wrapper<T>(private val continuation: Continuation<T>): Continuation<T> {
private inline fun wrap(block:() -> Unit) {
try {
myThreadLocal.set(myData)
block()
} finally {
myData = myThreadLocal.get()
}
}
override val context: CoroutineContext get() = continuation.context
override fun resume(value: T) = wrap { continuation.resume(value) }
override fun resumeWithException(exception: Throwable) = wrap { continuation.resumeWithException(exception) }
}
}
Để sử dụng nó trong coroutines, bạn quấn phối mà bạn muốn sử dụng với MyContext
và đặt cho nó giá trị ban đầu của dữ liệu của bạn. Giá trị này sẽ được đưa vào thread-local trên thread nơi coroutine được nối lại.
launch(MyContext(MyData(), CommonPool)) {
// do something...
}
Việc thực hiện ở trên cũng sẽ theo dõi bất kỳ thay đổi đối với thread-địa phương đã được thực hiện và lưu trữ nó trong bối cảnh này, vì vậy cách nhiều gọi này có thể chia sẻ dữ liệu "thread-địa phương" qua ngữ cảnh.
Nguồn
2017-09-14 20:08:43