Need to manually synchronize a synchronized list during iteration, when could it be avoided?

My question is about the synchronizedList Collections Class method.

Javadocs say:

It is imperative that the user manually synchronize on the returned list when iterating over it:

 List list = Collections.synchronizedList(new ArrayList()); ... synchronized(list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); } 

Although other methods do not require manual synchronization. I looked at the source code for the Collections class and found the shyncronization has already been reviewed for all methods like add

 public boolean add(E e) { synchronized(list) {return c.add(e);} } 

but not for the iterator method . I think the iterator method could also handle synchronization in the same way as above (this would avoid the extra work and manual synchronization for programmers). I'm sure there must be some specific reason for this, but am I missing it?

 public Iterator<E> iterator() { return c.iterator(); // Must be manually synched by user! } 

A way to avoid manual synchronization with Programmer

 public Iterator<E> iterator() { synchronized(list) { return c.iterator(); // No need to manually synched by user! } } 
+7
java collections list synchronization java.util.concurrent
source share
3 answers

I think the iterator method could also handle synchronization in the same way as the method described above

No, this is absolutely impossible.

The iterator does not control what your code does between calls to individual methods on it. This is the point. Your iteration code will call hasNext() and next() several times, and synchronization during these calls is possible, but it doesnโ€™t matter - itโ€™s important that no other code tries to change the list for the whole time you iterate.

So imagine a timeline:

 t = 0: call iterator() t = 1: call hasNext() t = 2: call next() // Do lots of work with the returned item t = 10: call hasNext() 

An iterator cannot synchronize between the end of the next() call at t = 2 and the hasNext() call at t = 10. So, if another thread tries (say) to add an item to the list at t = 7, how should the iterator stop it from doing this?

This is a common problem with synchronized collections: each individual operation is synchronized, while usually the whole operation needs to be synchronized.

+16
source share

If you do not synchronize the entire iteration, another thread may change the collection on repeat, which will throw a ConccurentModificationException.

In addition, the returned iterator is not thread safe.
They could fix this by wrapping the iterator in a SynchronizedIterator , which blocks each method in the iterator, but this will not help any of them; another thread can still change the collection between two iterations and break everything.

This is one of the reasons the Collections.synchronized*() methods are completely useless.
For more information on the proper streaming use of the collection, see my blog .

+3
source share

If you want to avoid manual serialization, you need to use a collection like java.util.concurrent.CopyOnWriteArrayList . Each time an object is added to the list, the basic data structure is copied to avoid the exception of parallel modification.

The reason you need manual serialization in Iterator in your example is because Iterator uses the same internal data structure as the list, but they are independent objects, and both Iterator and the list can be accessed by different streams in any arbitrary point in time.

Another example: make a local copy of the list and iterate over the copy.

0
source share

All Articles