Cómo usar código que se basa en ThreadLocal con corotines de Kotlin

Algunos frameworks JVM usan ThreadLocal para almacenar el context de llamada de una aplicación, como SLF4j MDC , gestores de transactions, administradores de security y otros.

Sin embargo, las corotinas de Kotlin se distribuyen en diferentes hilos, entonces, ¿cómo se puede hacer para que funcione?

(La pregunta está inspirada en el problema de GitHub )

El análogo de ThreadLocal a ThreadLocal es CoroutineContext .

Para interactuar con ThreadLocal -utilizando librerías-, necesita implementar un ContinuationInterceptor personalizado que sea compatible con thread-specific thread-locals.

Aquí hay un ejemplo. Supongamos que utilizamos algún marco que se basa en un ThreadLocal específico para almacenar algunos datos específicos de la aplicación ( MyData en este ejemplo):

 val myThreadLocal = ThreadLocal<MyData>() 

Para usarlo con corutinas, deberá implementar un context que mantenga el valor actual de MyData y lo MyData en el ThreadLocal correspondiente cada vez que la corutina se reanude en un hilo. El código debería verse así:

 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) } } } 

Para usarlo en sus corotines, ajuste el despachador que desea usar con MyContext y MyContext el valor inicial de sus datos. Este valor se colocará en el thread-local en el hilo donde se reanuda la coroutine.

 launch(MyContext(MyData(), CommonPool)) { // do something... } 

La implementación anterior también haría un seguimiento de los cambios en el hilo local que se realizó y lo almacenará en este context, por lo que de esta manera, la invocación múltiple puede compartir datos "thread-local" a través del context.

  • Kotlin Process Collection En Paralelo?
  • "+" En Kotlin Coroutines?
  • Cómo volver a intentar el retroceso exponencial en corotines de kotlin
  • Corutinas paralelas de Kotlin
  • Limpiar el uso de Coroutines en Kotlin con el soporte de testing unitaria
  • ¿Cuál es la forma correcta de usar las extensiones de Anko Coroutines?
  • Fan-out / fan-in - canal de resultado de cierre
  • Corutinas de testing unitaria en el hilo de UI
  • Kotlin: ArrayIndexOutOfBoundsException durante la conversión de DispatchTask a cadena
  • Kotlin coroutine traga exception
  • Tramos de resorte con capucha de spring que no anidan en corotina Kotlin