提问者:小点点

在多线程环境中使用HashMap进行定期更新


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

我试图解决一个简单的问题,我只需要缓存在内存中的服务器信息,以便更快地访问。所以我使用了hashmap。我需要确保内存中的服务器信息不过时,缓存中的所有服务器都有响应。

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

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

在这里,第一个线程经常运行15秒,第二个DB线程每5分钟运行一次。

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

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


共2个答案

匿名用户

并发HashMap保证这一点:

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

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

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

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

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

匿名用户

如果您需要确保数据展示一致性,并且每个线程都需要有最新的数据视图,请使用Collection. synizedMap(map)。如果性能至关重要,并且每个线程只将数据插入到映射中,读取发生的频率较低,请使用ConCurrentHashMap。

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

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

希望这有帮助。