线程安全版本 Kotlin 中的 ObservableProperty

Thread safe version ObservableProperty in Kotlin

提问人:Boris 提问时间:11/16/2023 更新时间:11/16/2023 访问量:24

问:

我的应用程序中有以下类:

class SomeService {

    @Volatile
    var property: String? = null

    fun loadProperty() {
        // this code loads property value from external source
    }

}
  • 应用程序中只有一个实例SomeService
  • loadProperty按给定计划从单个线程执行
  • 应用程序的其他线程可能会到达someService.property
  • @Volatile确保螺纹安全

现在我需要对值更改的事实进行一些后处理。 为此,Kotlin 提供了以下结构:

var property: String? by Delegates.observable(null) { _, _, newValue ->
    println(newValue)
}

但是,这种结构不是线程安全的,而不允许添加。 是否有任何现成的 Kotlin 结构来表示线程安全可观察性? 或者编写我自己的支持线程安全的类版本是唯一的选择?@VolatileObservableProperty

Kotlin 线程安全

评论

0赞 broot 11/16/2023
你有没有在外面设置过?如果没有,那么我认为您实际上并不需要可观察属性 - 只需将您的后处理放在 .如果我们不控制谁/在哪里更改属性的值,则 Observable 属性是好的。propertyloadProperty()loadProperty()

答:

2赞 Sweeper 11/16/2023 #1

应用委托属性的转换后,您会注意到类中不再有任何可以添加到的属性。@Volatile

private val property$delegate =
    object : ObservableProperty<String?>(null) {
        override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = ...
    }

var property: String?
    get() = property$delegate.getValue(this, this::property)
    set(value: String?) = property$delegate.setValue(this, this::property, value)

@Volatile不能继续下去,因为它从未真正改变过,它不能继续下去,因为它不再有后盾。property$delegateproperty

这基本上意味着您需要制作自己的.实际需要的是(来源)中的这个属性:ObservableProperty@VolatilevalueObservableProperty

public abstract class ObservableProperty<V>(initialValue: V) : ReadWriteProperty<Any?, V> {
    // this needs to be volatile
    private var value = initialValue

现在知道了这一点,编写自己的易失性版本很容易:

inline fun <V> Delegates.volatileObservable(initialValue: V, crossinline onChange: (property: KProperty<*>, oldValue: V, newValue: V) -> Unit) =
    object: ObservableVolatileProperty<V>(initialValue) {
        override fun afterChange(property: KProperty<*>, oldValue: V, newValue: V) =
            onChange(property, oldValue, newValue)
    }

abstract class ObservableVolatileProperty<V>(initialValue: V) : ReadWriteProperty<Any?, V> {
    @Volatile
    private var value = initialValue

    protected open fun afterChange(property: KProperty<*>, oldValue: V, newValue: V) {}

    override fun getValue(thisRef: Any?, property: KProperty<*>) = value

    // @Synchronized is needed if you are setting it from multiple threads
    @Synchronized
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
        val oldValue = this.value
        this.value = value
        afterChange(property, oldValue, value)
    }
}