【问题标题】:Usage of HashMap in a multi-threaded environment for regular update在多线程环境中使用 HashMap 进行定期更新
【发布时间】:2014-08-11 19:22:33
【问题描述】:

我有一个 Java 应用程序,我在其中将其他服务器的 IP 集保存在内存中的哈希映射中。哈希映射包含服务器实例 ID 到服务器 IP 地址之间的映射。我还在数据库中维护这些服务器信息以保持持久性。

我正在尝试解决一个简单的问题,我只需要将服务器信息缓存在内存中以便更快地访问。所以我为此使用了hashmap。而且我需要确保内存中的服务器信息不是陈旧的,并且缓存中的所有服务器都是响应的。

所以我创建了两个单独的后台守护线程

  • 一个线程从哈希图中获取每个条目并 ping 所有条目。如果任何服务器没有响应,则它会从哈希图中删除该条目。
  • 另一个线程基本上将数据库条目与此哈希映射缓存同步。因此,它会查询所有条目数据库,并删除哈希图中不存在于 DB 中的条目,对于 DB 中的新条目,它会 ping 每个条目并添加到哈希图中。

这里第一个线程频繁运行,假设每 15 秒运行一次,第二个数据库线程每 5 分钟运行一次。

由于这里的两个线程都在更新缓存,所以我使用了 ConcurrentHashMap,因为它会被同步。即便如此,当我阅读多篇文章、文档和一些 stackoverflow 帖子时,我看到多个线程更新 hashmap 是有风险的,比如当一个线程迭代 hashmap 时,另一个线程可能会被触发并开始更新 hashmap。

那么我该如何在这里使用不同的方法来解决这个问题,这样我就不会在应用程序性能、时间和空间复杂性方面干扰 JVM,并确保我的哈希图中始终只有响应式服务器条目.

【问题讨论】:

  • 你能澄清你的担忧吗?多个线程迭代哈希图不一定是问题。你在担心什么?
  • 另外,有理由使用 2 个线程吗?为什么不让一个线程操作缓存呢?
  • 我没有看到 2 个线程在 hashmap 上迭代的问题,但我担心的是 1 个线程正在添加条目,而另一个线程正在添加/删除条目。尽管这些操作非常少见,但由于我们要更新来自 2 个不同实体的哈希图,应用程序的性能会受到影响吗?
  • 不,不会有性能问题。

标签: java hashmap synchronization concurrenthashmap


【解决方案1】:

ConcurrentHashMap 保证这一点:

视图的迭代器是一个“弱一致”的迭代器,它永远不会 抛出 ConcurrentModificationException,并保证遍历 构造迭代器时存在的元素,并且可以 (但不保证)反映之后的任何修改 建设。

这意味着在最坏的情况下,一个线程所做的更新直到下一次迭代才会被第二个线程看到。让我们看看这对您的应用程序意味着什么:

如果在 ping 线程运行时同步线程添加了新服务器,则在此迭代中可能不会 ping。它将仅在下一次迭代中被 ping,15 秒后。只要您考虑到这种行为,这似乎就不是问题(即,如果您不运行第三个线程来删除在过去 15 秒内没有被 ping 过的任何东西或类似的东西)

如果服务器在 ping 进行时被同步线程删除,服务器可能仍会被 ping,但服务器的记录仍会从缓存中删除。同样,这不是问题。

如果 ping 线程在同步进行时删除了服务器,则同步线程可能仍会在缓存中看到该服务器。再说一次,我认为这不是问题。

【讨论】:

  • 很高兴收到回复。如果我们经常从 ConcurrentHashMap 中添加/删除,是否会影响该应用程序的性能?根据 techboost 提供的链接java.dzone.com/articles/java-7-hashmap-vs,ConcurrentHashMap 在性能方面更快更明显。您对此有何看法?
  • 您的应用程序所做的每一件事都有相关的性能成本。如果您需要准确估计几种技术替代方案的性能,我建议您自己进行基准测试。但总的来说,Java 的并发数据结构确实很优秀,比自己加锁要好。
【解决方案2】:

如果您需要确保数据一致性,并且每个线程都需要拥有最新的数据视图,请使用 Collections.synchronizedMap(map)。如果性能很关键,则使用 ConcurrentHashMap,每个线程只向映射中插入数据,读取发生的频率较低。

有一篇很好的文章用实际用例解释了 java 中地图的内部深层概念/工作原理:

http://java.dzone.com/articles/java-7-hashmap-vs

希望这会有所帮助。

【讨论】:

  • 感谢您的链接。感谢您的回复。
猜你喜欢
  • 2013-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-01
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多