Provide LazyThreadSafetyMode.PUBLICATION: concurrent non-blocking initializations, single publication.
This commit is contained in:
@@ -4,12 +4,78 @@ package test.utils
|
||||
import kotlin.*
|
||||
import kotlin.test.*
|
||||
import java.io.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.concurrent.thread
|
||||
import org.junit.Test as test
|
||||
|
||||
class LazyJVMTest {
|
||||
|
||||
@test fun synchronizedLazy() {
|
||||
val counter = AtomicInteger(0)
|
||||
val lazy = lazy {
|
||||
val value = counter.incrementAndGet()
|
||||
Thread.sleep(100)
|
||||
value
|
||||
}
|
||||
|
||||
val accessThreads = listOf(lazy, lazy).map { thread { it.value } }
|
||||
accessThreads.forEach { it.join() }
|
||||
|
||||
assertEquals(1, counter.get())
|
||||
}
|
||||
|
||||
@test fun externallySynchronizedLazy() {
|
||||
val counter = AtomicInteger(0)
|
||||
var initialized: Boolean = false
|
||||
val runs = ConcurrentHashMap<Int, Boolean>()
|
||||
val lock = Any()
|
||||
|
||||
val initializer = {
|
||||
val value = counter.incrementAndGet()
|
||||
runs += (value to initialized)
|
||||
Thread.sleep(100)
|
||||
initialized = true
|
||||
value
|
||||
}
|
||||
val lazy1 = lazy(lock, initializer)
|
||||
val lazy2 = lazy(lock, initializer)
|
||||
|
||||
val accessThreads = listOf(lazy1, lazy2).map { thread { it.value } }
|
||||
accessThreads.forEach { it.join() }
|
||||
|
||||
assertEquals(2, counter.get())
|
||||
for ((counter, initialized) in runs) {
|
||||
assertEquals(initialized, counter == 2, "Expected uninitialized on first, initialized on second call: initialized=$initialized, counter=$counter")
|
||||
}
|
||||
}
|
||||
|
||||
@test fun publishOnceLazy() {
|
||||
val counter = AtomicInteger(0)
|
||||
var initialized: Boolean = false
|
||||
val runs = ConcurrentHashMap<Int, Boolean>()
|
||||
|
||||
val initializer = {
|
||||
val value = counter.incrementAndGet()
|
||||
runs += (value to initialized)
|
||||
Thread.sleep((3 - value) * 100L)
|
||||
initialized = true
|
||||
value
|
||||
}
|
||||
val lazy = lazy(LazyThreadSafetyMode.PUBLICATION, initializer)
|
||||
|
||||
val accessThreads = listOf(lazy, lazy).map { thread { it.value } }
|
||||
accessThreads.forEach { it.join() }
|
||||
|
||||
assertEquals(2, counter.get())
|
||||
assertEquals(2, lazy.value)
|
||||
for ((counter, initialized) in runs) {
|
||||
assertFalse(initialized, "Expected uninitialized on first and second run")
|
||||
}
|
||||
}
|
||||
|
||||
@test fun lazyInitializationForcedOnSerialization() {
|
||||
for(mode in listOf(LazyThreadSafetyMode.SYNCHRONIZED, LazyThreadSafetyMode.NONE)) {
|
||||
for(mode in listOf(LazyThreadSafetyMode.SYNCHRONIZED, LazyThreadSafetyMode.PUBLICATION, LazyThreadSafetyMode.NONE)) {
|
||||
val lazy = lazy(mode) { "initialized" }
|
||||
assertFalse(lazy.isInitialized())
|
||||
val lazy2 = serializeAndDeserialize(lazy)
|
||||
|
||||
Reference in New Issue
Block a user