Why do we use synchronized collection if it doesn't guarantee the synchronized access on iterators?

295 Views Asked by At

For example, in the code below, we have to wrap list in a synchronized block when doing the iteration. Does the Collections.synchronizedList make the list synchronized? Why do we do this if it doesn't provide any convenience? Thanks!

List<Integer> list = Collections.synchronizedList( new ArrayList<>(Arrays.asList(4,3,52)));

synchronized(list) { 
      for(int data: list)
         System.out.print(data+" "); 
}
4

There are 4 best solutions below

0
On BEST ANSWER

See https://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html

The reason is that iteration is accomplished via multiple calls into the collection, which must be composed into a single atomic operation.

Also see https://www.baeldung.com/java-synchronized-collections

1
On

Wrapper is used to synchronize addition and removal elements from wrapped collection.

JavaDoc mentions that iteration is not synchronized an you need to synchronize it yourself.

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

But other access operations are thread-safe and also establish happens before relation (since they use synchronized).

0
On

Why do we do this if it doesn't provide any convenience

That it does not help you when iterating is not the same as providing no convenience.

All of the methods - get, size, set, isEmpty etc - are synchronized. This means that they have visibility of all writes made in any thread.

Without the synchronization, there is no guarantee that updates made in one thread are visible to any other threads, so one thread might see a size of 5 which another sees a size of 6, for example.

The mechanism for making the list synchronized is to make all of its methods synchronized: this effectively means that the body of the method is wrapped in a synchronized (this) { ... } block.

This is still true of the iterator() method: that too is synchronized. But the synchronized block finishes when iterator() returns, not when you finish iterating. It's a fundamental limitation of the way the language is designed.

So you have to help the language by adding the synchronized block yourself.

0
On

Collections.synchronizedList method synchronises methods like add, remove. However, it does not synzhronize iterator() method. Consider the following scenario:

  • Thread 1 is iterating through the list
  • Thread 2 is adding an element into it

In this case, you will get ConcurrentModificationException and hence, it's imperative to synzhronize the calls to iterator() method.