crazymind
crazymind

Reputation: 169

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

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+" "); 
}

Upvotes: 0

Views: 295

Answers (4)

Darshan Mehta
Darshan Mehta

Reputation: 30839

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.

Upvotes: 0

Andy Turner
Andy Turner

Reputation: 140484

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.

Upvotes: 2

togise
togise

Reputation: 298

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

Upvotes: 2

Ivan
Ivan

Reputation: 8758

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).

Upvotes: 0

Related Questions