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

时间:2014-08-11 19:22:34

标签: java hashmap synchronization concurrenthashmap

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

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

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

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

这里第一个线程频繁运行让我们说evey 15秒,第二个DB线程每5分钟运行一次。

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

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

2 个答案:

答案 0 :(得分:6)

ConcurrentHashMap保证:

  

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

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

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

如果在执行ping操作时同步线程删除了 ,服务器可能仍会被ping,但服务器的记录仍将从缓存中删除。再次,不是问题。

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

答案 1 :(得分:1)

如果需要确保数据一致性,请使用Collections.synchronizedMap(map),并且每个线程都需要具有最新的数据视图。如果性能至关重要,请使用ConcurrentHashMap,并且每个线程仅将数据插入到地图中,读取的频率会降低。

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

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

希望这有帮助。