I'm looking at the static method
Collections.synchronizedList(List<T> list)
Javadoc says
It is imperative that the user manually synchronize on the returned list when iterating over it...
What's the purpose of creating a synchronized list if I still have to manually synchronize it?
The reason why you would use
Collections.synchronizedList(List<T> list)
is because all the methods but the iterator are synchronized using the list itself as the mutex so you don't have to do
synchronized(list) {
list.add(type);
}
Instead you can just do
list.add(type);
and it will be thread safe.
The only method which isn't synchronized is when iterating the list. The list iterator can't be return in a synchronized fashion, since you will be iterating through it afterwards which is why it is required to manually synchronize the list. So in conclusion, you only have to synchronize the list when iterating over it, everything else you don't have to.
The java collections tutorial explains this. Basically, each iteration reauires multiple calls to the underlying collection. These calls muct be atomicised as a single 'transaction'.
Related
I'm reading the java official doc regarding wrappers implementation, which are static methods in Collections used to get synchronized collection, for example : List<Type> list = Collections.synchronizedList(new ArrayList<Type>());
...
the thing that I did not understand is the following (I quote from the java doc ) :
A collection created in this fashion is every bit as thread-safe as a normally synchronized collection, such as a Vector.
In the face of concurrent access, it is imperative that the user manually synchronize on the returned collection when iterating over it. The reason is that iteration is accomplished via multiple calls into the collection, which must be composed into a single atomic operation...
how it could be every bit as thread-safe an need to manually synchronize when iterating ??
It is thread safe in the sense that each of it's individual methods are thread safe, but if you perform compound actions on the collection, then your code is at risk of concurrency issues.
ex:
List<String> synchronizedList = Collections.synchronizedList(someList);
synchronizedList.add(whatever); // this is thread safe
the individual method add() is thread safe but if i perform the following:
List<String> synchronizedList = Collections.synchronizedList(someList);
if(!synchronizedList.contains(whatever))
synchronizedList.add(whatever); // this is not thread safe
the if-then-add operation is not thread safe because some other thread might have added whatever to the list after contains() check.
There is no contradiction here: collections returned from synchronizedXyz suffer the same shortcoming as synchronized collections available to you directly, namely the need to manually synchronize on iterating the collection.
The problem of external iteration cannot be solved by a better class design, because iterating a collection inherently requires making multiple calls to its methods (see this Q&A for detailed explanation).
Note that starting with Java 1.8 you can iterate without additional synchronization using forEach method of your synchronized collection*. This is thread-safe, and comes with additional benefits; see this Q&A for details.
The reason this is different from iterating externally is that forEach implementation inside the collection takes care of synchronizing the iteration for you.
I have a question. I think i know the answer but for some reason i prefer to ask for it here.
So here is the scenario:
I have an Object which has a list as a field. Then i have a method that returns the list as an unmodifiableList.
The Oject class has other methods that add elements to the list.
So lets imagine a case where one thread is iterating throught the unmodifiable list and another thread that is adding elements to the list using the Object class method.
How do i make this thread safe? If i synchronize the unmodifiableList and the list itselft will it make it thread safe? After all they are two different object where the unmodifiableList has a field which is the naked list itselft.
You need to make the "naked" list synchronized:
private List<Foo> list = Collections.synchronizedList(new ArrayList<Foo>());
But beware: that will only make sure the list internal state is coherent. As soon as you iterate on the list, you can't prevent a modification to the list to happen between two calls to the list iterator. So nothing will prevent a ConcurrentModificationException to happen in that case. To prevent that, you should not return any reference (even an indirect one) to the list. All modifications and iterations to the list should be encapsulated in your class, and properly synchronized.
You can return an unmodifiable-clone of original list to the caller.
The disadvantage is that the caller may end up with a "stale" version of the list. However, by this way you achieve safe iterations. In concurrent world, it is OK to return last successfully updated data to the caller.
public List<Thing> getThings() {
List<Thing> copytOfThings = new ArrayList<>();
copyOfThings.addAll(_things); //original list items.
return Collections.unmodifiableList(copyOfThings);
}
There are a couple of ways you could do this:
Return a copy of the list, rather than an unmodifiable view of it
Rather than using the iterator, use List.get(int)
My question is about synchronizedList method Collections Class.
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());
}
Though manually synchroniziation is not required for other methods. I looked into the source code of Collections class
and found shyncronization has already been taken care for all methods like add
public boolean add(E e) {
synchronized(list) {return c.add(e);}
}
but not for iterator method. I think iterator method could have also handled synchronization in the same fashion
as above method (it would have avoided the extra work i.e manual synchronization for programmers). i am sure there
must be some concrete reason behind it but i am missing it?
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
A way to avoid manual synchronization from Programmer
public Iterator<E> iterator() {
synchronized(list) {
return c.iterator(); // No need to manually synched by user!
}
}
I think iterator method could have also handled synchronization in the same fashion as above method
No, it absolutely couldn't.
The iterator has no control over what your code does between calls to the individual methods on it. That's the point. Your iteration code will call hasNext() and next() repeatedly, and synchronization during those calls is feasible but irrelevant - what's important is that no other code tries to modify the list across the whole time you're iterating.
So imagine a timeline of:
t = 0: call iterator()
t = 1: call hasNext()
t = 2: call next()
// Do lots of work with the returned item
t = 10: call hasNext()
The iterator can't synchronize between the end of the call to next() at t=2 and the call to hasNext() at t=10. So if another thread tries to (say) add an item to the list at t=7, how is the iterator meant to stop it from doing so?
This is the overall problem with synchronized collections: each individual operation is synchronized, whereas typically you want a whole chunky operation to be synchronized.
If you don't synchronize the entire iteration, another thread could modify the collection as you iterate, leading to a ConccurentModificationException.
Also, the returned iterator is not thread-safe.
They could fix that by wrapping the iterator in a SynchronizedIterator that locks every method in the iterator, but that wouldn't help either – another thread could still modify the collection between two iterations, and break everything.
This is one of the reasons that the Collections.synchronized*() methods are completely useless.
For more information about proper thread-safe collection usage, see my blog.
If you want to avoid manual synchronization, you have to use a Collection like java.util.concurrent.CopyOnWriteArrayList. Every time an object is added to the list, the underlying datastructure is copyied to avaoid a concurrent modification exception.
The reason why you need manual serialization on the Iterator in your example is that the Iterator uses the same internal datastructure as the list but they are independend objects and both Iterator and list can be accessed by different threads at any arbitrary moment in time.
Another aproach would be to make a local copy of the list and iterate over the copy.
I have a general question regarding synchronized List.
Lets say that in the constructor I am createing a list
List synchronizedList = Collections.synchronizedList(list);
and I have one method adds an object to the list.
public void add(String s){
synchronizedList.add(s)
}
There is another thread that checks every few seconds if there are a few rows , dump it to a file and deletes them all.
Now lets say I iterate each row and save it to the db.
after all iteration I clear the list.
How does the multithread support help me?
I could add an element to the list just before the clear() in the other thread occurs .
Unless I manage the lock myself (which I dont realy need a synched list for that ) it myself.
The synchronized list returned by Collections won't help in your case. It's only good if you need to guarantee serial access to individual method calls. If you need to synchronize around a larger set of operations, then you need to manually wrap that code in a synchronized block. The Javadoc states:
It is imperative that the user manually synchronize on the returned list when iterating over it.
If your list is used elsewhere you can at least safeguard it from individual method calls that would otherwise not be thread-safe. If you're entirely managing the list however, you can just add a synchronized block to your add method and use the same lock that you'll use when iterating over it.
synchronizedList indeed only guarantees that every method call on the list is synchronized. If you need multiple operations to be done in a synchronized way, you have to handle the synchronization yourself.
BTW, this is explicitely said in the javadoc for Collections.synchronizedList :
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());
}
synchronized list means that all the operations on that list are guaranteed to be atomic. The scenario you describe requires to have some locking outside the list. Consider semaphores or making synchronized block to implement monitors. Take a look at java.util.concurrent.
I have a very simple snippet of code that populates a vector, iterates through it, and then clears it. Here is basically what I'm trying in principle:
vector v = new Vector();
v.add(1);
v.add(2);
v.add(3);
ListIterator iter = v.listIterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
v.clear()
But I get a ConcurrentModificationException.
From reading up on this, apparently using "synchronized" in some fashion is the solution. But I'm seeing a couple different approaches and am wondering what is the best, simplest way to resolve this in my case (with no explicit threads involved)?
If no threads are involved, it's likely that the example you posted is incomplete.
This ConcurrentModificationException can happen simply if you modify the collection while iterating over it.
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will thow this exception.
And the docs for Vector.listIterator() explicitly state that:
Note that the list iterator returned by this implementation will throw an UnsupportedOperationException in response to its remove, set and add methods unless the list's remove(int), set(int, Object), and add(int, Object) methods are overridden.
(Well actually that the docs for AbstractList.listIterator(int); Vector doesn't redefine that.)
Let me shorten that code for you:
Vector<Integer> v = new Vector<Integer>();
v.add(1);
v.add(2);
v.add(3);
for (Integer i: v) {
System.out.println(i);
}
v.clear();
You shouldn't use listIterator() unless you do forward and backward navigation. For simple iteration use the iterator() method, preferably in the for-each style I show above (where the actual iterator object is hidden from you).
And don't use Vector!!! Use ArrayList instead.