Kotlin 与 ConcurrentHashMap 的并发性,同时在不使用锁的情况下检索和删除

Lat*_*Dev 7 concurrency concurrenthashmap java.util.concurrent kotlin

我试图了解ConcurrentHashMap并看看我是否可以利用它而无需在我这边添加任何锁。ConcurrentHashMap一天开始时我有很多书。

class Z {
    val books: ConcurrentHashMap<String, Int> = ConcurrentHashMap()
    
    fun addBook(book: String, numberOfBooks: Int) {
        books[book] = numberOfBooks
    }
 
    fun doSomething(book: String) {
        val numberOfBooks = books.remove(book)
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的内容是线程安全的。但是现在,如果我需要添加验证只是为了确保在初始化期间不会添加两次这本书,我需要添加一个synchronized块只是为了确保我没有添加如下所示的内容。

class Z {
    val books: ConcurrentHashMap<String, Int> = ConcurrentHashMap()
    val lock = Any()
    fun addBook(book: String, numberOfBooks: Int) {
        synchronized(lock) {
            val existingBook = books[book]
            if(existingBook!=null)
                println("Book exists, BEWARE!!")
            books[book] = numberOfBooks
        }
    }
 
    fun doSomething(book: String) {
        var numberOfBooks : Int? 
        synchronized(lock)
            numberOfBooks=books.remove(book)
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法让我做到这一点。我讨厌添加一个synchronized块只是为了在其中放入日志语句。

gid*_*dds 8

你很幸运:Map接口有几个方法可以帮助以原子方式完成此类事情,因此ConcurrentHashMap中的线程安全。

\n

在这种情况下,您甚至不需要任何特殊的东西,只需显式调用put()方法,因为它返回前一个值(或者null如果没有值)。

\n

所以你可以简单地调整你的第一个例子:

\n
fun addBook(book: String, numberOfBooks: Int) {\n    val existingNumber = books.put(book, numberOfBooks)\n    if (existingNumber != null)\n        println("Book exists, BEWARE!!")\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\xa6 可以在没有任何同步的情况下完成您想要的操作。\xc2\xa0 (您失去了 Kotlin 的数组访问语法糖,但这在这里显然是不重要的。)

\n

其他可以原子地完成复杂事情的方法有compute()merge()putIfAbsent()replace()等等;值得仔细浏览一下该类,以便您可以识别它们有用的情况。\xc2\xa0 正如您清楚地知道的那样,同步会带来严重的性能损失,因此如果您可以在不牺牲性能的情况下避免它安全,这可能是一个巨大的胜利。

\n