How to refresh HashMap while clients read from it

后端 未结 3 999
误落风尘
误落风尘 2021-01-27 09:12

I have a static HashMap that is initialized on server startup. Clients initialize their data from this map when they login.
Now I need to refresh this map, but

相关标签:
3条回答
  • 2021-01-27 09:50

    Lets assume that "refresh" means that you want to replace all entries in the hashmap with a fresh set loaded from (say) a file.

    If the set of keys in the new mapping is a superset of the keys in the original mapping, AND if you application doesn't care if clients can set part of the old mapping and part of the new mapping at the same time, then you could use a ConcurrentHashMap instead of a HashMap, and replace the entries with a sequence of put calls.

    However, if keys are (or could be) different, or if the update needs to be atomic from the client's perspective then a ConcurrentHashMap is not going to work. Instead, you need to declare map as a volatile and implement your refresh() method as per your question.

    As you point out, using synchronized (or a single-writer-multiple-reader lock) is liable to lead to a concurrency bottleneck.


    Note: using a volatile is likely to give better performance than using a ConcurrentHashMap even in the cases where the latter is a viable solution.

    0 讨论(0)
  • 2021-01-27 10:00

    First of all your map needs to be declared as volatile in order to ensure that each thread has the last version of it, then here is how you could proceed:

    public void refresh() {
        synchronized (MyClass.class) {
            Map<String, Object> newMap = prepareData();
            map = Collections.unmodifiableMap(newMap);
        }
    }
    

    And your map would be declared as below:

    private static volatile Map<String, Object> map = ...
    
    0 讨论(0)
  • 2021-01-27 10:05

    If it's ok that clients have stale data, then all you need to do is create a new map and point your static reference at it. If a new client comes along while you're doing this then they get the stale data and no harm is done, if they turn up after the switch (reassignment) to the new values has occurred then they will get the new values. Job done.

    If it's not ok then you will also, probably, have to inform other clients that existed before the update about the change. In which case you want to use the observer pattern for the updates. In this pattern it's fine if the client connects during the update, because they will be updated as soon as possible after the update is complete.

    BTW: in all cases, you really shouldn't be using 'static' for anything. It'll only lead to problems down the line. Rather, create a non-static singleton that holds the map and inject that into your clients/services/whatever.

    0 讨论(0)
提交回复
热议问题