Kotlin-从两个线程访问集合时如何锁定它

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

想知道是否有人可以提供帮助,我正在尝试了解使用两个线程访问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) }
    }
}
kotlin concurrency synchronized
2个回答
0
投票

如果要锁定集合或任何对象以进行并发访问,则可以使用与Java的synchronized关键字几乎相同的结构。

因此,在访问此类对象时,您会这样做

fun someFun() {
    synchronized(yourCollection) {

    }
}

您还可以使用Java的synchronizedCollection类中的Collections方法,但这仅使单方法访问线程安全,如果必须通过iterate进行collection,则仍然必须手动处理同步。


0
投票

您仅同步获取器和设置器,因此,当您开始使用引用时,您已经进入列表,它已经被解锁。

Kotlin具有Mutex类,可用于对共享的可变对象进行锁定操作。 Mutex比Java的synchronized好,因为它挂起而不是阻塞协程线程。

您的示例在现实世界中可能是糟糕的设计,因为您的课程公开公开了可变的列表。但是要使其至少可以安全地修改列表:

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