From javadocs
Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet(); // Needn't be in synchronized block
...
synchronized(m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Two queries:
1) Is Set returned by m.keySet() also a collection wrapper or just an unsynchronized set?
EDIT:
2)Is it necessary to synchronize on m in
synchronized(m) { // Synchronizing on m, not s!
Can't we synchronize on s instead of m?
1: Yes it returns a synchronized set that shares a mutex with the Map.
2: Yes you need to hold the lock manually while iterating. If you don't changes can be made in between calls to next() and you'll still have problems. Remember it is part of the specification of HashMap that if another thread, for example does an m.put("foo", "bar");
in between two of your calls to i.next()
, then next()
will throw ConcurrentModificationException. To prevent this, you lock the whole map so nobody can change it until you're done with the iterator. Locking just the set wouldn't stop anybody from adding to the map.
If you need to iterate while concurrent access may be happening, you should look at implementations of ConcurrentMap to make your life a lot easier.
1) The set returned is a SynchronizedSet
that uses the same mutex to lock on.
2) The map does not synchronise on itself, rather a separate mutex object, so synchronizing on the map will not stop other threads in that have access to the map from modifying it. This would only work if all of the code that modified the map, also synchronized on the map. The map does synchronise on itself, but oddly refers to itself using a seperate mutex
variable. Therefore synchronising on the map will prevent other modifications to the map via the syncronised wrapper. Note that the same mutex is used in the synronised set returned by the keySet()
method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With