java - 同步不经常更新的 hashmap 的最佳方式

标签 java multithreading data-structures synchronization hashmap

我有一个我们在应用程序中使用的 HashMap。数据是在应用程序初始加载期间从数据库中填充的,然后它始终只被读取并且从不更新。会有多个线程不断读取数据。由于数据永远不会更新,我们目前不使用任何同步,只使用 HashMap。我们现在定义它的方式是:

private volatile Map<Integer, MyData> myMap = new HashMap<>();

现在我们想通过从数据库中重新填充来每天更新一次 map 中的数据。我打算做的是将数据从数据库获取到本地 map ,比如 myLocalMap 说每天午夜。一旦我将数据从 DB 加载到 myLocalMap,我将交换 myMap 以指向它。

所以我担心的是,在我执行 myMap = myLocalMap 时,是否有可能其他正在从 myMap 读取数据的线程得到一个空的或意想不到的结果? 如果是,我将不得不同步 myMap。对于同步,我有以下选项:

synchronized(myMap) {} OR // synchronize all map get and update operations
ConcurrentHashMap OR
Collections.synchronizedMap(myMap)

但我对使用同步犹豫不决,因为那样我也会同步所有读取。我认为每天同步一次 map 刷新过程会影响全天不断发生的所有 map 读取。这尤其糟糕,因为我的应用程序中有许多 map 是通过这种方式读取和更新的。有什么想法/意见吗?谢谢!

最佳答案

At the point where I do myMap = myLocalMap, is there a possibility that some other thread that is reading data from myMap get an empty or unexpected result?

不,没有。读写 are atomic对于引用变量,这意味着整个操作同时发生,并且在整个操作完成之前,其他线程看不到结果。因此,任何从“myMap”读取的线程都将得到旧的 myMap 或新的 myMap,但绝不会得到空的或不一致的结果。此外,在“myMap”上使用 volatile 关键字将意味着所有线程将始终知道新数据:如果 myMap 已更新,任何在之后启动的读取操作开始的更新操作将使用更新后的值。

来自 Oracle 的 Java 教程的支持文档:

  • Reads and writes are atomic for reference variables and for most primitive variables (all types except long and double).
  • any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable

Vogella :

If a variable is declared with the volatile keyword then it is guaranteed that any thread that reads the field will see the most recently written value.

同样来自 Vogella 的同一篇文章:

The Java language specification guarantees that reading or writing a variable is an atomic operation

另见 this引用,特别是“ list 3. 使用 volatile 变量进行安全的一次性发布”,它描述了与您的场景非常相似的场景。

顺便说一句,我同意 Giovanni 关于 ConcurrentHashMap 的观点。但在您的情况下,您不需要使用 ConcurrentHashMap,因为所有更新都发生在单个事务中,而您只是调整 Map 以指向新数据。

关于java - 同步不经常更新的 hashmap 的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22562165/

相关文章:

sql - 用户事件的数据库结构是否正确?

r - 使用 r (data.table/dplyr) 中的列表列

c++ - 链表的循环遍历

c# - 将秒表与异步方法一起使用

java - 在 XML 中存储二维表(决策表)以实现高效查询

java - 有什么方法可以像谷歌或雅虎那样实时获取股票报价吗?

java - 如何删除队列中的第二个元素?

c++ - c++进入临界区和上下文切换

java - 如何检查 POJO 的字段是否 100% 线程安全?

java - 如何删除 GridLayout 组合中行之间的间距?