多线程环境下如何修改Kotlin StateFlow内容?

How to modify Kotlin StateFlow content in a multi-threaded environment?

我有一个包含不可变数据结构的 MutableStateFlow。

必须通过附加值来更改此结构的内容(必须读取StateFlow.value,必须基于现有对象创建新对象,然后发出)。

在多线程环境下,一个线程读取SharedFlow的内容后,但在修改回写之前,内容可能会被另一个线程修改。然后第一个线程将覆盖更新。

如何确保修改在多线程环境中永远不会被覆盖?

到目前为止,我看到了三种解决方法:

还有其他选择吗?我是否缺少一些可以使用的扩展功能?

您可以使用公平 ReentrantLock,只需将您的读取和修改用锁包裹在里面,如

val lock = ReentrantLock(true) //true makes it fair, keeps the order
lock.withLock{ 
   //all the code written inside this block will be synchronized.
}

我建议这个方法优于其他方法,因为它很容易实现,而且对于工作队列,你必须不断地监听队列以获取下一个项目,而连续循环对于这种简单的事情来说是一个昂贵的解决方案。

如果您使用协程来处理它,则可以使用带有互斥锁的挂起函数。它就像一个不可重入的锁,但是在等待 withLock.

时暂停而不是阻塞
private val _myStateFlow: MutableStateFlow<List<Foo>> = ...
val myStateFlow: StateFlow<List<Foo>> get() = _myStateFlow
private val mutex = Mutex()

suspend fun addValue(foo: Foo) {
    mutex.withLock {
        _myStateFlow.value = _myStateFlow.value + foo
    }
}

如果您需要从线程而不是协程添加值,我会使用其他答案中的 ReentrantLock。

自 kotlinx.coroutines 1.5.1 https://github.com/Kotlin/kotlinx.coroutines/releases/tag/1.5.1 we can use MutableStateFlow.update. See https://github.com/Kotlin/kotlinx.coroutines/issues/2720 了解详情。