由多个线程修改的MutableMap和map.size不等于键计数



我使用的是Kotlin,我有一个用Key作为String的mutableMap,当我有两个线程试图访问并放入同一个键时,发生了一些奇怪的事情,我的日志显示映射大小是2(而不是1(,我也在那里记录键和值,但只有一个条目。。。

@Component
class CacheImpl {
protected val cache: MutableMap<String, String> = HashMap() //same behavior with ConcurrentHashMap
fun fetchFromCache(key: String) {
log.info("cache size: ${cache.size}")
log.info("cache keys: ${cache.keys}")
log.info("cache keys count: ${cache.keys.count()}")
cache.computeIfAbsent(id) {
key -> fetchFromClient(key)
}
}
}
fun serviceCall() {
// should fetch from client
val result1 = cache.fetchFromCache("123")
// should fetch from service
val result2 = cache.fetchFromCache("123")
}

所以我有两个线程同时调用serviceCall,在日志中我发现了

[thread: 2] - cache size: 0
[thread: 4] - cache size: 0
[thread: 2] - cache keys: []
[thread: 4] - cache keys: []
[thread: 2] - cache keys count: 2
[thread: 4] - cache keys count: 2
[thread: 2] - cache size: 2
[thread: 2] - cache keys count: 2
[thread: 2] - cache keys: [123]
[thread: 4] - cache size: 2
[thread: 4] - cache keys count: 2
[thread: 4] - cache keys: [123]

我也尝试过LinkedHashMap,它更奇怪,在LinkedHashMap中,你可以看到我的映射包含两个完全相同的键!

[thread: 2] - cache size: 0
[thread: 4] - cache size: 0
[thread: 2] - cache keys: []
[thread: 4] - cache keys: []
[thread: 2] - cache keys count: 2
[thread: 4] - cache keys count: 2
[thread: 2] - cache size: 2
[thread: 2] - cache keys count: 2
[thread: 2] - cache keys: [123,123]
[thread: 4] - cache size: 2
[thread: 4] - cache keys count: 2
[thread: 4] - cache keys: [123,123]
  • Map不应该总是只维护一个唯一的密钥吗
  • 为什么我的地图大小与键数不匹配

HashMap不是线程安全的,所以当你放入两个线程时,就会出现奇怪的场景。我建议你使用ConcurrentWeakMap。正如医生所说的

这是一个非常有限的实现,不适合作为通用映射替换。//它具有免锁的获取和放置功能,并带有同步的rehash,以实现简单性(以及在争用时更好的CPU使用率(

但它只确保映射操作是线程安全的,您必须使方法是线程安全。


@Synchronized
fun fetchFromCache(key: String) {
log.info("cache size: ${cache.size}")
log.info("cache keys: ${cache.keys}")
log.info("cache keys count: ${cache.keys.count()}")
cache.computeIfAbsent(id) {
key -> fetchFromClient(key)
}
}

同时,每次返回新对象时,您使用的密钥都会从fetchFromClient生成。这也是原因。如果要覆盖退出的值,则应使用putIfAbseent

最新更新