List<String> list = new ArrayList<String>();
list.add("a");
...
list.add("z");
synchronized(list) {
Iterator<String> i = list.iterator();
while(i.hasNext()) {
...
}
}
and
List<String> list = new ArrayList<String>();
list.add("a");
...
list.add("z");
List<String> synchronizedList = Collections.synchronizedList(list);
synchronized(synchronizedList) {
Iterator<String> i = synchronizedList.iterator();
while(i.hasNext()) {
...
}
}
Specifically, I'm not clear as to why synchronized
is required in the second instance when a synchronized list provides thread-safe access to the list.
The second code needs to be synchronized because of the way synchronized lists are implemented. This is explained in the javadoc:
The main difference between the two code snippets is the effect of the
add
operations:synchronizedList.get(..)
for example.If you don't lock around the iteration, you will get a ConcurrentModificationException if another thread modifies it during the loop.
Synchronizing all of the methods doesn't prevent that in the slightest.
This (and many other things) is why
Collections.synchronized*
is completely useless.You should use the classes in
java.util.concurrent
. (and you should think carefully about how you will guarantee you will be safe)As a general rule of thumb:
For much more information, see my blog
synchronizedList
only makes each call atomic. In your case, the loop make multiple calls so between each call/iteration another thread can modify the list. If you use one of the concurrent collections, you don't have this problem.To see how this collection differs from ArrayList.
Even though the list is cleared repeatedly, it prints the following because that wa the contents when the iterator was created.