Rasekaran
Rasekaran

Reputation: 364

Is there any Concurrent multi valued HashMap data structure in java?

I have a requirement to have key value pairs, where the value can be a set. This data structure should be thread safe to add remove elements to the set in a multi threaded environment.

My requirement is to create a subscription list, here people can subscribe for different topics. This subscription list should be concurrent, thread safe and fast. I was thinking about Using ConcurentHashMap and ConcurrentHashSet, this will not help me since, I have to put the syncronization block at the top level and it will block the entire map until the put/remove operation completes.

Upvotes: 6

Views: 3705

Answers (2)

errantlinguist
errantlinguist

Reputation: 3818

There is no pre-rolled solution, but it is possible to achieve thread-safe concurrency for simple values using a ConcurrentMap<K, Set<V>> which has Set<V> values made from ConcurrentMap<V, Boolean> using Collections.newSetFromMap(Map<V,Boolean>).

Then, to get each value set in an atomic way, use ConcurrentMap.computeIfAbsent(K, Function<? super K, ? extends Set<V>>):

ConcurrentMap<String, Set<Integer>> multimap = new ConcurrentHashMap<>();
Set<Integer> fooValues = multimap.computeIfAbsent("foo", key -> Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>()));

If you want your values to have a stable iteration order, you can use a ConcurrentSkipListSet to hold values instead:

ConcurrentMap<String, NavigableSet<Integer>> multimap = new ConcurrentHashMap<>();
NavigableSet<Integer> fooValues = multimap.computeIfAbsent("foo", key -> new ConcurrentSkipListSet<>());

Likewise, in order to remove Set<V> value holder instances in a thread-safe fashion, you can use ConcurrentMap.computeIfPresent(K, BiFunction<? super K,? super Set<V>,? extends Set<V>>):

public static <K, V> void remove(final ConcurrentMap<K, Collection<? extends V>> multimap, final K key,
        final V value) {
    multimap.computeIfPresent(key, (k, oldValues) -> {
        final Collection<? extends V> newValues;
        if (oldValues.remove(value) && oldValues.isEmpty()) {
            // Remove the empty set from the multimap
            newValues = null;
        } else {
            newValues = oldValues;
        }
        return newValues;
    });
}

Note that there is no "ConcurrentHashSet" class provided by the Java core libraries.

Upvotes: 8

Roberto Attias
Roberto Attias

Reputation: 1903

you write "the value can be a set", but don't mention what the key is. In any case, Hashtable, the first map that was present in Java, is thread safe wrt adding/removing/replacing key,value pairs.

You can create a thread-safe Set with one of the methods described here. Whether that set is stored as value in an hashmap makes no difference.

Upvotes: -1

Related Questions