同步不常更新的hashmap的最佳方式 [英] Best way to synchronize infrequently updated hashmap

查看:230
本文介绍了同步不常更新的hashmap的最佳方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

现在我们要通过从数据库重新填充,每天更新一次这个数据。我计划做的是将数据从数据库中获取到本地地图,说 c> myLocalMap 每天在午夜说一次。一旦我将数据从DB加载到 myLocalMap ,我将只交换 myMap 来指向这个。



所以我的关注是,在我做的这个点上,我的myMap = myLocalMap ,是否有一种其他正在读取的线程的可能性来自 myMap 的数据会获得空的或意外的结果?
如果是,我将不得不同步 myMap 。为了同步,我有以下选项:

  synchronized(myMap){} OR //同步所有地图获取和更新操作
ConcurrentHashMap OR
Collections.synchronizedMap(myMap)

但我犹豫使用同步,因为那时我正在同步所有的读取。我认为,一天一次的刷新过程同步地图会影响到一天中不断发生的地图的所有读数。这是特别糟糕的,因为我的应用程序中有很多地图已经被读取和更新了。任何想法/评论?谢谢!

解决方案


在我做myMap = myLocalMap的时候,是否有可能性
那些从myMap读取数据的其他线程会得到一个空的或
意外的结果?


没有没有。阅读并撰写参考变量的是原子的,这意味着整个操作直到整个操作完成后,其他线程才会显示结果。因此,从'myMap'读取任何线程都可以获取旧的myMap或新的myMap,但永远不会得到空或不一致的结果。另外,在myMap上使用 volatile 关键字将意味着所有线程都将始终知道新数据:如果myMap已更新,则任何已启动的读操作> 之后,更新操作将使用该更新的值。



支持Oracle Java教程中的文档:



  • 读取和写入对于引用变量和大多数原始变量(除long和double之外的所有类型)是原子的。

  • 任何写入volatile变量的写入都会建立与该变量后续读取相关的发生关系。


Vogella


如果一个变量用volatile关键字声明,那么它是
,保证读取该字段的任何线程都将看到最多的
近y写入价值。


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


Java语言规范保证读取或写入
变量是一个原子操作


另外请参阅参考,具体来说清单3.使用volatile变量安全的一次性出版物描述了一个非常类似于你的场景。



我同意Giovanni关于ConcurrentHashMap的方式。但是在您的情况下,您不需要使用ConcurrentHashMap,因为您的所有更新都会在单个事务中进行,您只是将地图调整为指向新数据。


I have a HashMap that we use in our application. The data is populated from database during application initial load and then it's always just read and never updated. There will be multiple threads constantly reading the data. Since the data is never updated, we currently don't use any synchronization and is using just the HashMap. The way we define this now is:

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

Now we want to update this data in map once a day by re-populating from the database. What I'm planning to do is get the data from database to a local map say myLocalMap say everyday at midnight. Once I have the data loaded from DB to myLocalMap I will just swap myMap to point to this.

So my concern is, 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? If yes, I will have to synchronize myMap. For synchronization I have the below options:

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

But I'm hesitant to use synchronization because then I'm synchronizing all the reads too. I think synchronizing the map for once a day process of refreshing will impact all reads of the map that constantly occurs all through the day. This is especially bad since I have many maps in my application that are read and updated this way. Any thought/comments? Thanks!

解决方案

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?

No there is not. Reads and writes are atomic for reference variables which means the entire operation happens all at once and the results aren't visible to other threads until the entire operation is finished. Therefore, any thread reading from 'myMap' will get either the old myMap or the new myMap, but will never get an empty or inconsistent result. Additionally, using the volatile keyword on 'myMap' would mean that all threads will always be aware of fresh data: if myMap has been updated, any read operations that were initiated after the update operation started will use that updated value.

Supporting documentation from Oracle's Java tutorial:

  • 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.

Also from the same article on Vogella:

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

Also see this reference, specifically "Listing 3. Using a volatile variable for safe one-time publication" which describes a scenario very similar to yours.

I agree with Giovanni about ConcurrentHashMap by the way. But in your case you don't need to use ConcurrentHashMap since all of your updates occur in a single transaction and you are just adjusting the Map to point to the new data.

这篇关于同步不常更新的hashmap的最佳方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆