Reputation: 364
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
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
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