일부 JVM 프레임 워크는 SLF4j MDC, 트랜잭션 관리자, 보안 관리자 등과 같은 응용 프로그램의 호출 컨텍스트를 저장하기 위해 ThreadLocal
을 사용합니다.ThreadLocal에 의존하는 코드를 Kotlin 코 루틴과 함께 사용하는 방법
그러나 Kotlin 코 루틴은 다른 스레드에 전달되므로 어떻게 작동시킬 수 있습니까?
(문제가 GitHub issue에서 영감) 이일부 JVM 프레임 워크는 SLF4j MDC, 트랜잭션 관리자, 보안 관리자 등과 같은 응용 프로그램의 호출 컨텍스트를 저장하기 위해 ThreadLocal
을 사용합니다.ThreadLocal에 의존하는 코드를 Kotlin 코 루틴과 함께 사용하는 방법
그러나 Kotlin 코 루틴은 다른 스레드에 전달되므로 어떻게 작동시킬 수 있습니까?
(문제가 GitHub issue에서 영감) 이ThreadLocal
에 코 루틴의 아날로그 CoroutineContext
입니다.
라이브러리를 사용하여 ThreadLocal
과 상호 운용하려면 프레임 워크 관련 스레드 로컬을 지원하는 사용자 정의 ContinuationInterceptor
을 구현해야합니다.
다음은 예입니다. 우리가 (이 예에서는 MyData
)를 일부 응용 프로그램 별 데이터를 저장하는 특정 ThreadLocal
에 의존하는 일부 프레임 워크를 사용한다고 가정하자 :
val myThreadLocal = ThreadLocal<MyData>()
는 코 루틴과 함께 사용하려면 컨텍스트를 구현해야하는 현재 값인 MyData
을 유지하고 해당 coroutine이 스레드에서 재개 될 때마다 해당 ThreadLocal
에 넣습니다. 코드는 다음과 같아야합니다
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) }
}
}
당신이 MyContext
로 사용하고 그것을 데이터의 초기 값을 부여 할 디스패처 포장, 당신의 코 루틴에서 사용하십시오. 이 값은 coroutine이 다시 시작되는 스레드의 thread-local에 저장됩니다.
launch(MyContext(MyData(), CommonPool)) {
// do something...
}
위의 구현은 또한 스레드 로컬 이루어졌다에 대한 변경 사항을 추적 할 것이며, 이러한 맥락에 저장되므로이 방법은 여러 호출 컨텍스트를 통해 "스레드 로컬"데이터를 공유 할 수 있습니다.