【问题标题】:How to prevent threads from reading inconsistent data from ConcurrentHashMap?如何防止线程从 ConcurrentHashMap 中读取不一致的数据?
【发布时间】:2022-01-18 01:03:53
【问题描述】:

我使用ConcurrentHashMap<String, String> 作为缓存,执行读取操作以验证元素是否已在缓存中,并执行写入操作以将元素添加到缓存中。

所以,我的问题是:始终读取最新的 ConcorrentHashMap 值的最佳做法是什么?

我要保证数据的一致性,不要出现这样的情况:

  1. 使用map.get("key") 方法,第一个线程验证映射中尚不存在此键,然后执行map.put("value")
  2. 第二个线程在第一个线程将元素放入地图之前读取数据,导致数据不一致。

代码示例:

Optional<String> cacheValue = Optional.ofNullable(cachedMap.get("key"));

if (cacheValue.isPresent()) {
    // Perform actions

} else {
    cachedMap.putIfAbsent("key", "value");
    // Perform actions
}

如何确保我的ConcurrentHashMap 已同步并且不会检索到不一致的数据?

我应该在同步块中执行这些映射操作吗?

【问题讨论】:

  • Javadoc 说什么不清楚?
  • 如果您阅读 Javadoc,您会看到单个插入和删除是原子发生的,但对读者的唯一保证是他们不会看到部分完成的更改,因此不会有 ConcurrentModificationException扔了。
  • 是的@SolomonSlow!就是你说的! "在第一个线程调用 put("key", data) 之前,第二个线程调用 map.get("key")"
  • 对不起,我删除了那条评论,我想我误读了你的问题。
  • 你知道computeIfAbsent方法吗?

标签: java multithreading concurrency concurrenthashmap


【解决方案1】:

你可能需要这样做:

if (cachedMap.putIfAbsent("key", "value") == null) {
    // Perform actions "IS NOT PRESENT" 
} else {
    // Perform actions "IS PRESENT"
}

在两次检查中执行它显然不是原子的,所以如果您在缓存中放入错误值时遇到问题,那么这很可能是您的问题。

【讨论】:

  • 感谢您的回复,我理解您的观点。我还没有想到这种构建 if 语句的方式。但是,我无法在我的情况下应用它,因为我要保存的值仅在此条件下计算
  • 那么你需要使用computeIfAbsent之类的方法。
【解决方案2】:

始终读取最新的 ConcurrentHashMap 值的最佳做法是什么?

Oracle 的Javadoc for ConcurrentHashMap 说:“检索反映了最近完成的更新操作在开始时保持的结果。”换句话说,无论何时您调用map.get(...)map 上的任何其他方法,您始终处理的是“最新”内容。

*但是*

够了吗?也许不吧。如果您的程序线程期望映射中的两个或多个键之间存在任何类型的一致性,或者如果您的线程期望存储在映射中的内容与存储在其他地方的内容之间存在任何类型的一致性,那么您将需要提供线程之间的一些显式更高级别的同步。

我无法针对令您困惑的问题提供具体的示例,因为您的问题并未真正说明问题是什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-17
    相关资源
    最近更新 更多