从不同的流对同一变量进行线程安全访问(Kotlin)

qgelzfjb  于 2023-01-17  发布在  Kotlin
关注(0)|答案(1)|浏览(225)

这段代码是线程安全的吗?我需要一个同步块或类似的东西吗?source1和source2无尽的Kotlin流

viewModelScope.launch {
    var listAll = mutableListOf<String>()
    var list1 = mutableListOf<String>()
    var list2 = mutableListOf<String>()

    launch {
        source1.getNames().collect { list ->
            list1 = list

            listAll = mutableListOf()
            listAll.addAll(list1)
            listAll.addAll(list2)

            //then consume listAll as StateFlow or return another flow with emit(listAll)
        }
    }

    launch {
        source2.getNames().collect { list ->
            list2 = list

            listAll = mutableListOf()
            listAll.addAll(list2)
            listAll.addAll(list1)

            //then consume listAll as StateFlow or return another flow with emit(listAll)
        }
    }
}
f0ofjuux

f0ofjuux1#

此代码不是线程安全的。
但是,它是从viewModelScope.launch调用的,默认情况下,Dispatchers.Main运行在Dispatchers.Main上。因此,内部的launch块将被顺序调用。这意味着,最终您将获得由第二个launch块产生的结果。
要实现异步行为,您需要使用viewModelScope.launch(Dispatchers.Default)。在这种情况下,您的代码可能会触发并发修改异常。
要同步它,您可能需要使用Java的Collections.synchronizedList,它在一个线程对列表执行操作时阻塞列表,因此其他线程无法执行修改。
或者使用Mutex手动执行同步。

val mutex = Mutex()  

 viewModelScope.launch(Dispatchers.Default) {       

     launch {
         mutex.withLock {
             ... // Your code 
         }    
     }

     launch {
         mutex.withLock {
             ... // Your code 
         }    
     }
 }

读取official Kotlin guide to shared mutable state
毕竟,我很难想象你会在现实生活中真正使用这些代码。你可能不需要异步行为,不使用两个启动块就可以了。或者你应该重新考虑你的设计,以避免需要手动同步两个协程。

相关问题