Reputation: 21
I am using a concurrent hashmap of structure
Map<Set<Date>, Map<String, Object>> SampleMap
The Map used inside the given map (Map<String, Object>
) is also a concurrent hashmap,
but set is a only TreeSet
type.
Still I get concurrent Modification exception when I add following line in logs,
logger.debug("sampleMap.keySet() + ". Size is " + sampleMap.keySet().size()");
and also in some other parts of same class dealing with this map.
This map is extensively used in Batch process by multiple threads to put and remove values in map and java version used is 1.5.
I think the exception is due to Treeset and also i find there is no similar implementation of concurrent handling collection for type Set.
It would be great if any one confirm whether my thinking over given issue is correct and also please suggest solution for this problem?
Upvotes: 2
Views: 294
Reputation: 533442
Since you need to be able to "modify" the key, you need to follow this pattern
// lock the collection
Map<String, Object> values = map.remove(key);
key = new TreeSet<String>(key);
// modify copy of key
map.put(key, values);
// unlock the collection.
As you are performing an operation which ConcurrentMap does not support, you have to use your own locking. You can use a plain HashMap or LinkedHashMap with synchronized or ReentrantReadWriteLock.
You can create a Concurrent set using
// Added in Java 1.6
Set<String> set = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
// or to be sorted
Set<String> set = Collections.newSetFromMap(new ConcurrentSkipListMap<String, Boolean>());
However, you can't change the contents of a key so what you should be using is
Set<String> key = Collections.unmodifiableSet(treeSet);
// or to be sure its not modified
Set<String> key = Collections.unmodifiableSet(new TreeSet<String>(treeSet));
A simple example of why you cannot change a key after using it in a Map.
Set<String> key1 = new TreeSet<String>();
Map<Set<String>, Boolean> map = new ConcurrentHashMap<Set<String>, Boolean>();
map.put(key1, true);
System.out.println("Is the map ok? "+map.containsKey(key1));
key1.add("hello");
System.out.println("Is the map ok? "+map.containsKey(key1));
prints
Is the map ok? true
Is the map ok? false
The common behaviour is that it can no longer see the key in the map. This is because the map places the key into a bucket based on its hashCode. If the hashCode changes, it can be in the wrong bucket so when it looks for it, it can't find it.
Upvotes: 3