99b38ccb74
Using `ReflectionProperties.lazy` is incorrect because it allows several threads to observe different resulting values if they're computing it simultaneously (unlike `lazy(PUBLICATION)`, which always returns the value that "won the race"). In the case of property delegates, for example, if we're invoking `isAccessible = true` and then `getDelegate()` concurrently, it might happen that when some thread invokes `getDelegate()`, it gets the underlying Field object which was written by another thread and which has not yet been made accessible, leading to IllegalPropertyDelegateAccessException. #KT-27585 Fixed
40 lines
993 B
Kotlin
Vendored
40 lines
993 B
Kotlin
Vendored
import java.util.concurrent.atomic.AtomicInteger
|
|
import java.util.concurrent.atomic.AtomicReference
|
|
import java.util.concurrent.CyclicBarrier
|
|
import kotlin.concurrent.thread
|
|
import kotlin.reflect.jvm.*
|
|
|
|
const val N_THREADS = 50
|
|
|
|
class Delegate {
|
|
operator fun getValue(x: Any?, y: Any?): String = "OK"
|
|
operator fun setValue(x: Any?, y: Any?, z: String) {}
|
|
}
|
|
|
|
var property by Delegate()
|
|
|
|
fun main() {
|
|
val reference = ::property
|
|
|
|
val gate = CyclicBarrier(N_THREADS + 1)
|
|
var fail = AtomicReference<Throwable?>(null)
|
|
var finished = AtomicInteger(0)
|
|
for (i in 0 until N_THREADS) {
|
|
thread {
|
|
gate.await()
|
|
reference.isAccessible = true
|
|
try {
|
|
reference.getDelegate()!!
|
|
} catch (e: Throwable) {
|
|
fail.set(e)
|
|
}
|
|
finished.incrementAndGet()
|
|
}
|
|
}
|
|
|
|
gate.await()
|
|
|
|
while (finished.get() != N_THREADS) Thread.sleep(25L)
|
|
fail.get()?.let { throw it }
|
|
}
|