Kotlin - 从两个线程访问集合时如何锁定集合
Kotlin - How to lock a collection when accessing it from two threads
想知道是否有人可以提供帮助,我正在尝试了解在 Kotlin 中使用两个线程访问集合的正确方法。
下面的代码模拟了我在实时系统中遇到的问题。一个线程遍历集合,但另一个线程可以删除该数组中的元素。
我已经尝试将@synchronized 添加到集合中getter,但这仍然给我一个并发修改异常。
谁能告诉我正确的做法是什么?
class ListTest() {
val myList = mutableListOf<String>()
@Synchronized
get() = field
init {
repeat(10000) {
myList.add("stuff: $it")
}
}
}
fun main() = runBlocking<Unit> {
val listTest = ListTest()
launch(Dispatchers.Default) {
delay(1L)
listTest.myList.remove("stuff: 54")
}
launch {
listTest.myList.forEach { println(it) }
}
}
如果您想锁定一个集合或任何对象以进行并发访问,您可以使用与 java 的 synchronized
关键字几乎相同的构造。
所以在访问这样的对象时你会做
fun someFun() {
synchronized(yourCollection) {
}
}
您也可以使用 java 的 Collections
class 中的 synchronizedCollection
方法,但是如果您必须 iterate
超过 collection
,您仍然需要手动处理同步。
您只是在同步 getter 和 setter,因此当您开始使用您到达列表的引用时,它已经解锁。
Kotlin 具有 Mutex class 可用于锁定共享可变对象的操作。 Mutex 比 Java 的 synchronized
更好,因为它暂停而不是阻塞协程线程。
您的示例在现实世界中设计不佳,因为您的 class 公开公开了一个可变列表。但至少要确保修改列表是安全的:
class ListTest() {
private val myListMutex = Mutex()
private val myList = mutableListOf<String>()
init {
repeat(10000) {
myList.add("stuff: $it")
}
}
suspend fun modifyMyList(block: MutableList<String>.() -> Unit) {
myListMutex.withLock { myList.block() }
}
}
fun main() = runBlocking<Unit> {
val listTest = ListTest()
launch(Dispatchers.Default) {
delay(1L)
listTest.modifyMyList { it.remove("stuff: 54") }
}
launch {
listTest.modifyMyList { it.forEach { println(it) } }
}
}
如果您不使用协程,而不是 Mutex()
,您可以使用 Any
而不是 withLock
,就像您在Java 以防止同步块中的代码同时来自 运行。
想知道是否有人可以提供帮助,我正在尝试了解在 Kotlin 中使用两个线程访问集合的正确方法。
下面的代码模拟了我在实时系统中遇到的问题。一个线程遍历集合,但另一个线程可以删除该数组中的元素。
我已经尝试将@synchronized 添加到集合中getter,但这仍然给我一个并发修改异常。
谁能告诉我正确的做法是什么?
class ListTest() {
val myList = mutableListOf<String>()
@Synchronized
get() = field
init {
repeat(10000) {
myList.add("stuff: $it")
}
}
}
fun main() = runBlocking<Unit> {
val listTest = ListTest()
launch(Dispatchers.Default) {
delay(1L)
listTest.myList.remove("stuff: 54")
}
launch {
listTest.myList.forEach { println(it) }
}
}
如果您想锁定一个集合或任何对象以进行并发访问,您可以使用与 java 的 synchronized
关键字几乎相同的构造。
所以在访问这样的对象时你会做
fun someFun() {
synchronized(yourCollection) {
}
}
您也可以使用 java 的 Collections
class 中的 synchronizedCollection
方法,但是如果您必须 iterate
超过 collection
,您仍然需要手动处理同步。
您只是在同步 getter 和 setter,因此当您开始使用您到达列表的引用时,它已经解锁。
Kotlin 具有 Mutex class 可用于锁定共享可变对象的操作。 Mutex 比 Java 的 synchronized
更好,因为它暂停而不是阻塞协程线程。
您的示例在现实世界中设计不佳,因为您的 class 公开公开了一个可变列表。但至少要确保修改列表是安全的:
class ListTest() {
private val myListMutex = Mutex()
private val myList = mutableListOf<String>()
init {
repeat(10000) {
myList.add("stuff: $it")
}
}
suspend fun modifyMyList(block: MutableList<String>.() -> Unit) {
myListMutex.withLock { myList.block() }
}
}
fun main() = runBlocking<Unit> {
val listTest = ListTest()
launch(Dispatchers.Default) {
delay(1L)
listTest.modifyMyList { it.remove("stuff: 54") }
}
launch {
listTest.modifyMyList { it.forEach { println(it) } }
}
}
如果您不使用协程,而不是 Mutex()
,您可以使用 Any
而不是 withLock
,就像您在Java 以防止同步块中的代码同时来自 运行。