2

I have a singleton map used throughout which means I cannot simply reassign the entire map. I control the map so I can make it a ConcurrentHashMap.

I am populating it in a separate thread (I am using Quartz to create a scheduled job). I need to remove all of the values from the map and them put a bunch of new values in. I am concerned, though, that there will be CPU cycles where the map is empty where a separate thread might read the map. I do this population of the map every N seconds.

If I wasn't concerned about making the operation atomic, I could just do:

Map<String, String> newMap = ...;
myMap.clear(); 
// What if a read happens here?
myMap.putAll(newMap);

I don't know very much about synchronization, but I don't think putting this in a synchronized block will help, since it is not this code that is doing the reading.

ConcurrentHashMap provides several useful atomic operations, but it doesn't look like it provides any that help me with this problem.

Jeremy
  • 5,365
  • 14
  • 51
  • 80
  • You could use an `AtomicReference` rather than talk to the `Map` directly. Alternatively you could look at [`Map.replaceAll`](https://docs.oracle.com/javase/10/docs/api/java/util/Map.html#replaceAll(java.util.function.BiFunction)) - although its atomicity depends on your `Map` - if it's a `HashMap`, you're out of luck. – Boris the Spider Aug 24 '18 at 21:13
  • Well, what is your current synchronization strategy for reading/writing from/to the map (when you're not replacing everything)? Do you currently use a `ConcurrentHashMap` for those operations, or do you synchronize access by locking on some object, or do use a `ReentrantReadWriteLock`? – Janus Varmarken Aug 24 '18 at 21:14
  • @JanusVarmarken if it's written once then shared, there might not yet be any synchronization strategy. – Boris the Spider Aug 24 '18 at 21:15
  • 1
    @BoristheSpider I added some more information. I can use a ConcurrentHashMap. Also, this map is written continually. (Every N seconds) – Jeremy Aug 24 '18 at 21:18
  • @JanusVarmarken My strategy is to use a ConcurrentHashMap but I can change the code as needed. – Jeremy Aug 24 '18 at 21:18
  • @Jeremy `ConcurrentHashMap` manages locking internally and provides improved performance by only locking a region of the map, and you [cannot use external synchronization](https://stackoverflow.com/a/21658411/1214974) to achieve atomicity of compound operations. What is your use case? Do you only have a single writer (the thread you mention in the post) and multiple readers? In that case, you could probably get away with using a `ReentrantReadWriteLock` for synchronizing access to a regular `HashMap`. – Janus Varmarken Aug 24 '18 at 21:43
  • 1
    This sort of sounds like an X-Y problem because the actual usage of the map is left unclear. If you're using the map as a cache, you're probably way better off using a tried-and-tested library implementation such as [Caffeine](https://github.com/ben-manes/caffeine/wiki) for Java 8 and above or [Guava caching](https://github.com/google/guava/wiki/CachesExplained) pre Java 8. – Mick Mnemonic Aug 24 '18 at 22:09
  • 1
    Given that it is a singleton can't you return the wrapper to the clients of the singleton? The wrapper that will delegate calls to the internal immutable map and replace it in the wrapper atomically. Every client would see either previous or the new version of the map. – Roman-Stop RU aggression in UA Aug 24 '18 at 22:09

0 Answers0