如果您正在寻找 ThreadLocal 作为性能优化,以确保每个线程都获得它自己的某个临时对象的副本,那么您应该继续为此目的使用 ThreadLocal。协程可能比线程多得多,并且为每个协程保留一些临时对象的副本可能弊大于利。
如果您正在寻找 ThreadLocal 作为在方法调用周围传递一些上下文的方法,那么我强烈建议考虑将此上下文显式传递到您的函数中或使用一些依赖注入框架来做到这一点。
如果您确实需要传递一些上下文,但由于某些技术原因您不能显式传递它也不能使用 DI(这就是您将使用 ThreadLocal 与线程的地方),您可以将CoroutineContext 与协程一起使用。步骤是:
使用以下模板定义您自己的协程上下文元素类:
class MyContextElement : AbstractCoroutineContextElement(MyContextElement) {
companion object Key : CoroutineContext.Key<MyContextElement>
// you state/code is here
}
创建元素的实例并在启动协程时将其传递给协程构建器。以下示例使用launch 协程构建器,但它适用于所有协程构建器(async、produce、actor 等)
launch(MyContextElement()) {
// the code of your coroutine
}
您可以使用+ 运算符将您的上下文与其他上下文元素组合(有关详细信息,请参阅"Combining Contexts" in the guide)
在您的协程代码中,您始终可以从coroutineContext 中检索您的元素。所有标准构建器都将CoroutineScope 实例纳入其范围,这使其coroutineContext 属性可用。如果您深入到挂起函数的调用堆栈中,那么您可以定义自己的 coroutineContext() 帮助函数来检索当前上下文,直到它在未来的更新之一中进入标准库。详情请见KT-17609。
有了coroutineScope,很容易检索你的元素:
val myElement = coroutineScope[MyContextElement]