Kotlin delegate 属性 by lazy 是线程本地的

Kotlin delegate property by lazy that is thread local

是否有一种简单的方法可以像 ThreadLocal 一样获取每个线程计算的委托 属性 by lazy 的值?

LazyThreadSafetyMode 控制并发初始化,.NONE 通过允许多个线程接收不同的值来接近所需的功能,但后续 post 初始化调用引用同一对象,无论线程如何,都返回相同的奇异值,在某些情况下返回 null

无论是并发初始化还是延迟初始化,属性 都会为每个线程缓存一个唯一值。

Kotlin delegates 很容易通过您自己的实现进行扩展。

  • 您可以让您的代表维护一个 ThreadLocal<T>initialValue 由传递的函数计算:

    class ThreadLocalLazy<T>(val provider: () -> T) :ReadOnlyProperty<Any?, T> {
        private val threadLocal = object : ThreadLocal<T>() {
            override fun initialValue(): T = provider()
        }
    
        override fun getValue(thisRef: Any?, property: KProperty<*>): T =
            threadLocal.get()
    }
    
  • 或者用ThreadLocal<Lazy<T>>为每个线程维护一个Lazy<T>,这样你的委托就可以自己实现Lazy<T>

    class ThreadLocalLazy<T>(val provider: () -> T) : Lazy<T> {
        private val threadLocal = object : ThreadLocal<Lazy<T>>() {
            override fun initialValue(): Lazy<T> = 
                lazy(LazyThreadSafetyMode.NONE, provider)
        }
    
        override val value get() = threadLocal.get().value
        override fun isInitialized() = threadLocal.get().isInitialized()
    }
    

这是一个创建委托实例的便捷函数:

fun <T> threadLocalLazy(provider: () -> T) = ThreadLocalLazy(provider)

那就把一个属性委托给threadLocalLazy { ... }吧。使用示例:

class Example {
    val threadId by threadLocalLazy { Thread.currentThread().id }
}

fun main(args: Array<String>) {
    val example = Example()
    repeat(3) {
        thread {
            println(example.threadId) // should print three different numbers
        }
    }
}