Kotlin 中的线程安全版本 ObservableProperty

问题描述 投票:0回答:1

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

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)
}

但是这个结构不是线程安全的,同时不允许添加

@Volatile
。 是否有任何现成的 Kotlin 结构可以表示线程安全的 observable? 或者编写我自己的支持线程安全的
ObservableProperty
类版本是唯一的选择?

kotlin thread-safety
1个回答
0
投票

应用委托属性翻译后,您会注意到您的类中不再有任何可以添加

@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$delegate
因为它实际上从未改变,并且它无法继续
property
因为它不再有支持字段。

这基本上意味着您需要自己制作

ObservableProperty
。实际上需要的是
@Volatile
value
中的
ObservableProperty
属性(source):

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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.