I decided to dig into source code a bit and noticed that Collections.synchronizedList(List)
is implemented as follows:
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<T>(list) :
new SynchronizedList<T>(list));
}
where the SynchronizedList
nested class is:
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
public boolean More ...equals(Object o) {
synchronized(mutex) {return list.equals(o);}
}
//ommited
public void add(int index, E element) {
synchronized(mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized(mutex) {return list.remove(index);}
}
//rest is ommited
}
As can bee seen, the class useses a private
lock object to provide thread-safety. But the documentation allows us to iterate over it using locking on the objetct returned by the factory method.
It is imperative that the user manually synchronize on the returned list when iterating over it:
So, we use different locks for iterating and modifying list (add
, remove
, etc).
Why is it considered to be safe?