From Javadocs for Collections class:
public static <T> List<T> synchronizedList(List<T> list)
Returns a synchronized (thread-safe) list backed by the specified list. In order to guarantee serial access, it is critical that all access to the "backing list" is accomplished through the returned list.
Do I understand correctly, that "backing list" means method argument (list), so below the line of code List<String> mySyncList = Collections.synchronizedList(origList);
I shall never do anything like origList.anyMethodCall(), including: origList.add("blabla")
, or origList.remove("blabla")
, origList.set(1, "blabla")
? Though it compiles! Can I access "backing list" in a way not making structural modifications (origList.contains("blabla")
)? I guess, I can, but it is also "access to the backing list"! And one is supposed to follow official Oracle docs...
Is that right, that problem arises ONLY when origList STRUCTURALLY MODIFIED AFTER I obtained iterator from mySyncList and BEFORE I finished using this iterator?
If so, am I right, that if thread-3 structurally modifies origList, then iterating mySyncList in any other thread gives ConcurrentModificationException, but there are absolutely no problems so far as either thread-3 modifies origList non-structurally (contains()), or thread-3 modifies origList structurally but there is no iteration in mySyncList (mySyncList.add, mySyncList.remove, ...)?
public static void main(String[] args) {
List<String> origList = new ArrayList<>();
origList.add("one");
origList.add("two");
origList.add("three");
List<String> mySyncList = Collections.synchronizedList(origList);
origList.add("blabla"); // prohibited by Oracle ??? :)))
origList.add("blabla"); // prohibited by Oracle ??? :)))
origList.add("blabla"); // prohibited by Oracle ??? :)))
origList.add("blabla"); // prohibited by Oracle ??? :)))
// now use mySyncList
System.out.println(mySyncList); // no problem so far
// P.S.: Maybe problem arises ONLY when origList STRUCTURALLY MODIFIED
// AFTER I obtained iterator from mySyncList and BEFORE I finished
// using this iterator? If so, such wording would be much preferable in
// official docs!
}
P.S. My question is different, and I do understand that:
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());
}
SO reseach did't yield answer, I diligently reviewed all the following:
Why do I need to synchronize a list returned by Collections.synchronizedList
Collections.synchronizedlist() remove element while iterating from end
What is the use of Collections.synchronizedList() method? It doesn't seem to synchronize the list
- What cause java.util.concurrentmodificationexception using Collections.synchronizedList?
THANKS TO GRAY ACCEPTED ANSWER BELOW I FINALLY CAME TO THE FOLLOWING CONCLUSION (my brief outline of Gray's answer):
After writing "List mySyncList = Collections.synchronizedList(origList)" it is recommended to write in next line "origList = null". In practice, guru never use origList anywhere later in code (in any thread, in entire prog).
Theoretically there is no problem to use origList later provided that it is not modified structurally (add, remove not called), but no one can safely guarantee only non-structural accesses in practice.
The ideology behind that is this: you converted origList into thread-safe mySyncList, and now use only mySyncList for multithreaded purposes and forget about origList !!!