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
39 lines
978 B
Kotlin
Vendored
39 lines
978 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.full.*
|
|
import kotlin.reflect.jvm.*
|
|
|
|
const val N_THREADS = 50
|
|
|
|
class C {
|
|
private fun function() {}
|
|
}
|
|
|
|
fun main() {
|
|
val instance = C()
|
|
val reference = C::class.functions.single { it.name == "function" }
|
|
|
|
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.javaMethod!!.invoke(instance)
|
|
} catch (e: Throwable) {
|
|
fail.set(e)
|
|
}
|
|
finished.incrementAndGet()
|
|
}
|
|
}
|
|
|
|
gate.await()
|
|
|
|
while (finished.get() != N_THREADS) Thread.sleep(25L)
|
|
fail.get()?.let { throw it }
|
|
}
|