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 toi.next(), thennext()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.