我有一个在应用程序中使用的 HashMap。数据是在应用程序初始加载期间从数据库填充的,然后它始终只是读取并且从不更新。会有多个线程不断地读取数据。由于数据永远不会更新,因此我们目前不使用任何同步,仅使用 HashMap。我们现在定义的方式是:
private volatile Map<Integer, MyData> myMap = new HashMap<>();
现在我们希望通过从数据库重新填充来每天更新一次地图中的数据。我打算做的是将数据从数据库获取到本地地图myLocalMap
每天半夜说。一旦我将数据从数据库加载到myLocalMap
我只会交换myMap
指出这一点。
所以我担心的是,在我做的那一刻myMap = myLocalMap
,是否有其他线程正在读取数据的可能性myMap
得到空的或意外的结果?
如果是的话,我将不得不同步myMap
。对于同步,我有以下选项:
synchronized(myMap) {} OR // synchronize all map get and update operations
ConcurrentHashMap OR
Collections.synchronizedMap(myMap)
但我对使用同步犹豫不决,因为那样我也会同步所有读取。我认为每天同步一次地图刷新过程会影响全天不断发生的所有地图读取。这尤其糟糕,因为我的应用程序中有许多地图都是通过这种方式读取和更新的。有什么想法/意见吗?谢谢!
当我执行 myMap = myLocalMap 时,是否有可能
从 myMap 读取数据的其他线程得到一个空或
意想不到的结果?
不,那里没有。读取和写入是原子的 http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html对于引用变量,这意味着整个操作同时发生,并且在整个操作完成之前结果对其他线程不可见。因此,任何从“myMap”读取的线程都将获得旧的 myMap 或新的 myMap,但永远不会获得空或不一致的结果。此外,使用volatile
“myMap”上的关键字意味着所有线程将始终了解新数据:如果 myMap 已更新,则启动的任何读取操作after启动的更新操作将使用该更新后的值。
Oracle Java 教程的支持文档:
- 对于引用变量和大多数原始变量(除 long 和 double 之外的所有类型),读取和写入都是原子的。
- 对易失性变量的任何写入都会与同一变量的后续读取建立发生之前的关系
Vogella http://www.vogella.com/tutorials/JavaConcurrency/article.html:
如果一个变量是用 volatile 关键字声明的,那么它就是
保证任何读取该字段的线程都会看到最多
最近写入的值。
同样来自关于 Vogella 的同一篇文章:
Java 语言规范保证读或写
变量是原子操作
另请参阅this https://www.ibm.com/developerworks/java/library/j-jtp06197/参考,特别是“清单 3. 使用易失性变量进行安全的一次性发布”,它描述了一种与您的情况非常相似的场景。
顺便说一下,我同意 Giovanni 关于 ConcurrentHashMap 的观点。但在您的情况下,您不需要使用 ConcurrentHashMap,因为所有更新都发生在单个事务中,并且您只需调整 Map 以指向新数据。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)