Provide lazy implementation with an external object to synchronize on.
This commit is contained in:
@@ -62,6 +62,12 @@ public fun lazy<T>(initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)
|
|||||||
* The [mode] parameter is ignored. */
|
* The [mode] parameter is ignored. */
|
||||||
public fun lazy<T>(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)
|
public fun lazy<T>(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer].
|
||||||
|
*
|
||||||
|
* The [lock] parameter is ignored.
|
||||||
|
*/
|
||||||
|
public fun lazy<T>(lock: Any?, initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)
|
||||||
|
|
||||||
private fun arrayCopyResize(source: dynamic, newSize: Int, defaultValue: Any?): dynamic {
|
private fun arrayCopyResize(source: dynamic, newSize: Int, defaultValue: Any?): dynamic {
|
||||||
val result = source.slice(0, newSize)
|
val result = source.slice(0, newSize)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public object Delegates {
|
|||||||
* the property delegate object itself is used as a lock.
|
* the property delegate object itself is used as a lock.
|
||||||
* @param initializer the function that returns the value of the property.
|
* @param initializer the function that returns the value of the property.
|
||||||
*/
|
*/
|
||||||
deprecated("Use lazy {} instead in kotlin package")
|
deprecated("Use lazy(lock) {} instead in kotlin package", ReplaceWith("lazy(lock, initializer)"))
|
||||||
public fun blockingLazy<T>(lock: Any?, initializer: () -> T): ReadOnlyProperty<Any?, T> = BlockingLazyVal(lock, initializer)
|
public fun blockingLazy<T>(lock: Any?, initializer: () -> T): ReadOnlyProperty<Any?, T> = BlockingLazyVal(lock, initializer)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -51,9 +51,11 @@ public enum class LazyThreadSafetyMode {
|
|||||||
|
|
||||||
private object UNINITIALIZED_VALUE
|
private object UNINITIALIZED_VALUE
|
||||||
|
|
||||||
private class LazyImpl<out T>(initializer: () -> T) : Lazy<T>(), Serializable {
|
private open class LazyImpl<out T>(initializer: () -> T) : Lazy<T>(), Serializable {
|
||||||
private var initializer: (() -> T)? = initializer
|
private var initializer: (() -> T)? = initializer
|
||||||
private volatile var _value: Any? = UNINITIALIZED_VALUE
|
private volatile var _value: Any? = UNINITIALIZED_VALUE
|
||||||
|
protected open val lock: Any
|
||||||
|
get() = this
|
||||||
|
|
||||||
override val value: T
|
override val value: T
|
||||||
get() {
|
get() {
|
||||||
@@ -62,7 +64,7 @@ private class LazyImpl<out T>(initializer: () -> T) : Lazy<T>(), Serializable {
|
|||||||
return _v1 as T
|
return _v1 as T
|
||||||
}
|
}
|
||||||
|
|
||||||
return synchronized(this) {
|
return synchronized(lock) {
|
||||||
val _v2 = _value
|
val _v2 = _value
|
||||||
if (_v2 !== UNINITIALIZED_VALUE) {
|
if (_v2 !== UNINITIALIZED_VALUE) {
|
||||||
_v2 as T
|
_v2 as T
|
||||||
@@ -83,6 +85,7 @@ private class LazyImpl<out T>(initializer: () -> T) : Lazy<T>(), Serializable {
|
|||||||
private fun writeReplace(): Any = InitializedLazyImpl(value)
|
private fun writeReplace(): Any = InitializedLazyImpl(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ExternallySynchronizedLazyImpl<out T>(override val lock: Any, initializer: () -> T): LazyImpl<T>(initializer)
|
||||||
|
|
||||||
private class UnsafeLazyImpl<out T>(initializer: () -> T) : Lazy<T>(), Serializable {
|
private class UnsafeLazyImpl<out T>(initializer: () -> T) : Lazy<T>(), Serializable {
|
||||||
private var initializer: (() -> T)? = initializer
|
private var initializer: (() -> T)? = initializer
|
||||||
|
|||||||
@@ -27,3 +27,20 @@ public fun lazy<T>(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
|
|||||||
LazyThreadSafetyMode.SYNCHRONIZED -> LazyImpl(initializer)
|
LazyThreadSafetyMode.SYNCHRONIZED -> LazyImpl(initializer)
|
||||||
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
|
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
|
||||||
|
* and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
|
||||||
|
*
|
||||||
|
* If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
|
||||||
|
*
|
||||||
|
* The returned instance uses the specified [lock] object to synchronize on.
|
||||||
|
* When the [lock] is not specified the instance uses itself to synchronize on,
|
||||||
|
* in this case do not synchronize from external code on the returned instance as it may cause accidental deadlock.
|
||||||
|
* Also this behavior can be changed in the future.
|
||||||
|
*/
|
||||||
|
public fun lazy<T>(lock: Any?, initializer: () -> T): Lazy<T> =
|
||||||
|
if (lock != null)
|
||||||
|
ExternallySynchronizedLazyImpl(lock, initializer)
|
||||||
|
else
|
||||||
|
LazyImpl(initializer)
|
||||||
@@ -17,6 +17,23 @@ class LazyValTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SynchronizedLazyValTest {
|
||||||
|
volatile var result = 0
|
||||||
|
val a by lazy(this) {
|
||||||
|
++result
|
||||||
|
}
|
||||||
|
|
||||||
|
test fun doTest() {
|
||||||
|
synchronized(this) {
|
||||||
|
// thread { a } // not available in js // TODO: Make this test JVM-only
|
||||||
|
result = 1
|
||||||
|
a
|
||||||
|
}
|
||||||
|
assertTrue(a == 2, "fail: initializer should be invoked only once")
|
||||||
|
assertTrue(result == 2, "fail result should be incremented after test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class UnsafeLazyValTest {
|
class UnsafeLazyValTest {
|
||||||
var result = 0
|
var result = 0
|
||||||
val a by lazy(LazyThreadSafetyMode.NONE) {
|
val a by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
|
|||||||
Reference in New Issue
Block a user