Provide lazy implementation with an external object to synchronize on.

This commit is contained in:
Ilya Gorbunov
2015-09-01 18:46:27 +03:00
parent 4fbf787f7d
commit b3073dbd2d
5 changed files with 46 additions and 3 deletions
@@ -30,7 +30,7 @@ public object Delegates {
* the property delegate object itself is used as a lock.
* @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)
/**
+5 -2
View File
@@ -51,9 +51,11 @@ public enum class LazyThreadSafetyMode {
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 volatile var _value: Any? = UNINITIALIZED_VALUE
protected open val lock: Any
get() = this
override val value: T
get() {
@@ -62,7 +64,7 @@ private class LazyImpl<out T>(initializer: () -> T) : Lazy<T>(), Serializable {
return _v1 as T
}
return synchronized(this) {
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
_v2 as T
@@ -83,6 +85,7 @@ private class LazyImpl<out T>(initializer: () -> T) : Lazy<T>(), Serializable {
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 var initializer: (() -> T)? = initializer
@@ -27,3 +27,20 @@ public fun lazy<T>(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
LazyThreadSafetyMode.SYNCHRONIZED -> LazyImpl(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)