Skip to content

Instantly share code, notes, and snippets.

@neworld
Created April 5, 2016 07:06
Show Gist options
  • Save neworld/843d99e7f7a783713b5593bba888249a to your computer and use it in GitHub Desktop.
Save neworld/843d99e7f7a783713b5593bba888249a to your computer and use it in GitHub Desktop.
package com.vinted.extensions
import kotlin.reflect.KProperty
/**
* @author Andrius Semionovas
* @since 2015-10-16
*/
class LazyVar<T> internal constructor(initializer: () -> T) {
companion object {
private object UNINITIALIZED_VALUE
}
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
private var initializer: (() -> T)? = initializer
@Suppress("UNCHECKED_CAST")
operator fun getValue(thisRef: Any?, propertyMetadata: KProperty<*>): T {
val v1 = _value
if (v1 !== UNINITIALIZED_VALUE) {
return v1 as T
}
return synchronized(this) {
val v2 = _value
if (v2 !== UNINITIALIZED_VALUE) {
v2 as T
} else {
_value = initializer!!.invoke()
initializer = null
_value as T
}
}
}
operator fun setValue(thisRef: Any?, propertyMetadata: KProperty<*>, value: T) {
synchronized(this) {
_value = value
initializer = null
}
}
}
fun <T> lazyVar(initializer: () -> T): LazyVar<T> = LazyVar(initializer)
package com.vinted.extensions
import org.junit.Test
import kotlin.concurrent.thread
import kotlin.test.assertEquals
/**
* @author Andrius Semionovas
* @since 2015-10-16
*/
class LazyVarTest {
var fixture: Int by lazyVar { 1 }
@Test
fun testLazyInitialization() {
assertEquals(1, fixture)
}
@Test
fun testOverrideInitializedVariable() {
assertEquals(1, fixture)
fixture = 2
assertEquals(2, fixture)
}
@Test
fun testSetVariableBeforeInitialization() {
fixture = 2
assertEquals(2, fixture)
}
@Test
fun testThreadSafe() {
val threadSafeLazyVar = ThreadSafeLazyVar(1)
val values: Array<Int> = Array(2) { 0 }
val t1 = thread { values[0] = threadSafeLazyVar.fixture }
val t2 = thread {
synchronized(threadSafeLazyVar.lock) {
if (!threadSafeLazyVar.initialized) {
threadSafeLazyVar.lock.wait()
}
}
threadSafeLazyVar.fixture = 2;
values[1] = threadSafeLazyVar.fixture
}
t1.join()
t2.join()
assertEquals(listOf(1, 2), values.toList())
}
}
class ThreadSafeLazyVar(val initValue: Int) {
@Volatile var initialized = false
val lock = Object()
var fixture: Int by lazyVar {
synchronized(lock) {
initialized = true
lock.notify()
}
Thread.sleep(100)
initValue
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment