Is there a simple way get a delegated property by lazy
's value computed per thread like ThreadLocal
?
LazyThreadSafetyMode
controls concurrent initialization, with .NONE
coming close to the desired functionality by allowing multiple threads to receive different values, but has subsequent post initialization calls referencing the same object, returning the same singular value regardless of thread, with some cases returning null
.
Regardless of concurrent initialization, or late initialization, the property would cache a unique value per thread.
The Kotlin delegates are easy to extend with your own implementation.
You can make your delegate maintain a ThreadLocal<T>
with initialValue
calculated by the function that is passed:
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()
}
Or maintain a Lazy<T>
per thread with ThreadLocal<Lazy<T>>
, so that your delegate can implement Lazy<T>
by itself:
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()
}
Here's a convenience function to create instances of the delegate:
fun <T> threadLocalLazy(provider: () -> T) = ThreadLocalLazy(provider)
Then just delegate a property to threadLocalLazy { ... }
. Usage example:
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
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With