3

I want to use a Comparator based key value Map. This will have reads and a rare write operation (once every 3 months through a scheduler). The initial load of the collection will be done at application startup. Also note that the write will:

  • Add a single entry to the Map
  • Will not modify any existing entry to the Map.

Will ConcurrentSkipListMap be a good candidate for this. Is the get operation on this allows access to multiple threads simultaneously? I'm looking for concurrent non blocking read but atomic write.

Kanishk
  • 506
  • 3
  • 14
  • 5
    I would be super suspicious of an application that you expected to stay running for three continuous months, but honestly any ConcurrentMap implementation will work here. – Louis Wasserman Dec 15 '16 at 22:10
  • 3
    Unless it's *extremely* expensive to load, I would go with an immutable map and just create a new one every 3 months. No need to worry about thread safety. – shmosel Dec 15 '16 at 22:11
  • 1
    Yes, as for all concurrent collections, its operations are thread-safe. It's also pretty clear from the javadoc. If you're only interested in get(), I wonder why you don't simply use a ConcurrentHashMap, which would be O(1) rather than O(log(n)). – JB Nizet Dec 15 '16 at 22:12
  • @JBNizet I was confused too, but the first sentence says "Comparator based." – Louis Wasserman Dec 15 '16 at 22:20
  • @LouisWasserman A comparator based map is useful if you need it to be sorted, or navigable. If get() is the only important operation, choosing it to be comparator-based is a bad choice IMO. Even if the key type doesn't have a proper hashCode/equals and can't be modified, extracting or wrapping the key into another object defining hashCode and equals would probably be more efficient than using a comparator. Don't you agree? – JB Nizet Dec 15 '16 at 22:24
  • 1
    I don't think I have nearly enough data to assume I know better than the OP for their situation. – Louis Wasserman Dec 15 '16 at 22:27
  • Whoa, let's not put the cart before the horse. We know your write frequency - what's your read frequency? Read concurrency? (how many threads do you want to access this at once?) How smart are the keys and the values that you will put in the map? Are they simple, like Strings and primitives, or will you put complex objects with behavior? How are you going to handle persistence? Unless you don't have a problem restarting from scratch on every program start, you'll need this. (maybe you have it already!) – Tassos Bassoukos Dec 15 '16 at 22:50
  • 1
    Honestly, I'd just use a volatile reference to a non synchronized map and replace it with a copy containing the new data once in a while. I really don't see why it would matter whether we have primitives or complex objects in the collection - that seems irrelevant for the given problem. The optimal solution performance wise should be identical independent if we have one or ten thousand readers. – Voo Dec 16 '16 at 10:02

3 Answers3

2

ConcurrentHashMap is exactly what you're looking for. From the Javadoc:

Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove). Retrievals reflect the results of the most recently completed update operations holding upon their onset. (More formally, an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value.)

That sounds like it satisfies your requirement for "concurrent non blocking read but atomic write".

Since you're doing so few writes, you may want to specify a high loadFactor and appropriate initialSize when creating the ConcurrentHashMap, which will prevent table resizing as you're populating the map, though this is a modest benefit at best. (You could also set a concurrencyLevel of 1, though Java 8's Javadoc seems to imply that is no longer used as a sizing hint.)

If you absolutely must have a SortedMap or NavigableMap, then ConcurrentSkipListMap is the out-of-the-box way to go. But I would double-check that you actually need the functionality provided by those interfaces (getting the first/last key, submaps, finding nearby entries, etc.) before using them. You will pay a steep price (log n vs. constant time for most operations).

Jason Hoetger
  • 7,543
  • 2
  • 16
  • 18
1

Since you are looking for concurrent operations you have basically 3 competitors. Hashtable, ConcurrentHashMap, ConcurrentSkipListMap (or Collections.synchronizedMap() but that's not efficient).

  • Out of these 3 latter 2 are more suitable for concurrent operation as they just lock the portion of map rather than locking the entire map like Hashtable.
  • Out of latter 2 SkipListMap uses skip list data structure which ensures average O(log n) performance for fast search and variety of operations.
  • It also offers number of operations that ConcurrentHashMap can't, i.e. ceilingEntry/Key(), floorEntry/Key(), etc. It also maintains a sort order which would otherwise have to be calculated.

Thus if you had asked only for faster search i'd have suggested ConcurrentHashMap, but since you have also mentioned 'rare write operations' and 'desired sorting' order I think ConcurrentSkipListMap wins the race.

skY
  • 111
  • 7
1

If you are willing to try third party code, you could consider a copy-on-write version of maps, which are ideal for infrequent writes. Here's one that came up via Googling:

https://bitbucket.org/atlassian/atlassian-util-concurrent/wiki/CopyOnWrite%20Maps

Never tried it myself so caveat emptor.

user949300
  • 15,364
  • 7
  • 35
  • 66