【问题标题】:ConcurrentHashMap atomic operation to remove all entries except oneConcurrentHashMap 原子操作删除除一个之外的所有条目
【发布时间】:2018-11-10 15:56:18
【问题描述】:

给定一个ConcurrentHashMap<String, String> 包含以下条目:

this.map = new ConcurrentHashMap<>();
this.map.put("user", "user description");
this.map.put("session", "session description");
this.map.put("test", "test description");

地图被多个线程访问。

如何以原子方式删除除session 之外的所有键?

在没有竞争条件的情况下,这段代码会按我的预期工作吗? forEach 方法是原子的吗?有没有其他方法可以原子地实现这一点?

map.forEach((key, value) -> {
    if (!key.equals("session")) {
        map.remove(key);
    }
});

【问题讨论】:

  • 我猜.equals("session) 是错字?而且您的实际代码确实有一个结束 "?
  • @Mark,是的,这是错字,而我的实际代码包含“。”。
  • “session”关联的值可以被其他线程修改吗?地图中是否总会有一个“会话”键?
  • @arshajii 不,与“会话”关联的值永远不会改变,但可以修改所有其他键。是的,会话始终存在于地图中。
  • 好的,在这种情况下,请查看下面的答案。

标签: java concurrency atomic concurrenthashmap


【解决方案1】:

您的forEach() 不会自动发生,因为每个remove() 调用都是独立同步的。

您可以尝试通过创建一张新地图并用它替换旧地图来做到这一点:

ConcurrentMap<String, String> newMap = new ConcurrentHashMap<>();
newMap.put("session", this.map.get("session"));
this.map = newMap;

在切换之前查看this.map 的线程将具有旧视图,但可以认为原子“删除”是在您分配新映射时发生的。唯一的另一个问题是,当另一个线程在第 2 行和第 3 行之间的原始映射中修改与 "session" 关联的值时(或者如果该键甚至不存在),但正如您在 your comment 中所说的那样,这永远不会发生。

【讨论】:

  • 您提出的解决方案对我有好处。我又想到了一个问题:forEach() 方法呢?是同步还是不同步?如果是,那么假设其中可能有很长的操作,如果两个线程尝试执行它会发生什么?一个人会等待另一个人,或者两者都会获得地图的副本/视图而不会阻塞?
  • 不,不是。为什么不直接测试一下?在 forEach 中添加一个 Thread.sleep(),并启动一个使用该地图的线程。你会知道的。
  • @JBNizet 是的,我开始像你写的那样玩它。我只是想让比我更有经验的人来证实我的猜测。
  • @Mariusz.v7 你也可以看看the source 看到这个。
猜你喜欢
  • 2012-11-23
  • 2014-05-15
  • 1970-01-01
  • 1970-01-01
  • 2022-07-26
  • 1970-01-01
  • 2018-01-05
  • 1970-01-01
  • 2016-08-02
相关资源
最近更新 更多