Making all the methods on a class individually synchronized doesn't make an aggregation ( calling them in a group ) of those methods thread safe. By wrapping the Iterator
in a synchronized block you are protecting that particular instance of the iterator from having its individual method called interspersed with other calls by multiple threads.
If I call .add()
once it is safe, if I need to call .add()
multiple times to complete a logical statement, there is no guarantee that someone else hasn't added something else or removed something else between my .add()
calls unless I block everything else from calling .add()
( or any other method ) by synchronizing
on the variable that represents the collection.
The Iterator
makes mutiple calls to the individual methods on the collection, they all have to be wrapped in a single synchronized
block to make them execute as a single transaction
of sorts. Examine the source code of the implemenation of Iterator
you will see what I mean. Here is the source code for List
it makes multiple individual calls to the underlying implementation, so they all need to be executed in uninterrupted order by the same thread to be deterministic.
@Override
public Iterator<A> iterator() {
if (tail == null)
return emptyIterator();
return new Iterator<A>() {
List<A> elems = List.this;
public boolean hasNext() {
return elems.tail != null;
}
public A next() {
if (elems.tail == null)
throw new NoSuchElementException();
A result = elems.head;
elems = elems.tail;
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
The source for AbstractList.iterator()
shows even more complicated logic that makes multiple calls.
A better wrapper is wrapping them in Immutable
collections, then you guarantee that nothing else can alter the underlying collection between calls.