我有一个Java应用程序,其中我在内存中的哈希映射中维护其他服务器的IP集。哈希映射包含服务器实例ID与服务器IP地址之间的映射。我还将这些服务器信息保存在数据库中以保持持久性。
我正在尝试解决一个简单的问题,我只需要在内存中缓存服务器信息以便更快地访问。所以我已经使用了hashmap。我需要确保内存中的服务器信息不是陈旧的,并且缓存中的所有服务器都是响应的。
所以我创建了两个单独的后台守护程序线程
这里第一个线程频繁运行让我们说evey 15秒,第二个DB线程每5分钟运行一次。
由于两个线程都在这里更新缓存,我使用了ConcurrentHashMap,因为它将被同步。即便如此,当我阅读多篇文章,文档和一些stackoverflow帖子时,我看到多个线程更新hashmap会有风险,比如当一个线程迭代hashmap时,其他线程可能会被触发并开始更新hashmap。
那么我如何使用不同的方法来解决这个问题,这样我就不会在应用程序性能,时间和空间复杂性方面打扰JVM,并确保我的hashmap中始终只有响应式服务器条目
答案 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
希望这有帮助。