CopyOnWriteArrayList and the ArrayList are part of the Collections framework. CopyOnWriteArrayList and ArrayList implement the List interface (just like Vector and LinkedList), but underlying implementations either support multi-threaded applications or single threaded applications.
In CopyOnWriteArrayList, each mutative operation e.g. add, set etc are done after creating a copy of the underlying array. Since it uses a ‘snapshot’ style iterator and copy never changes for the lifetime of the iterator, it does not get a ConcurrentModificationException. In this lifetime, any modifications on the original one will not be available to that iterator which is working on the copy. You cannot use its iterator to do mutations otherwise it will return UnsupportedOperationException.
Both support generics, so any element can be added including null.
In ArrayList, if one thread if try to iterate over the list, while another one is modifying the list e.g. adding a new element or setting some element to a different value, then we are bound to get ConcurrentModificationException. Now, in contrast to this CopyOnWriteArrayList does not give mutation rights to anyone for the lifetime of the iterator.
CopyOnWriteArrayList is highly efficient if the number of iterations is far higher (upwards of 90+% reads) than the number of mutations. If most of the operations are only random access based then it is better to use ReadWriteLock.
ArrayList was introduced in JDK 1.2 whereas CopyOnWriteArrayList was introduced in JDK 1.5.
Let’s take an example of CopyOnWriteArrayList and its inter-workings with its iterator.
/* * CopyOnWriteArrayList and its iterator */ List<Integer> mSimpleList = new CopyOnWriteArrayList<Integer>(); mSimpleList.add(0); mSimpleList.add(1); mSimpleList.add(2); /* * Now we get the iterator. After getting it, mIterator has the current copy. * So, In our system we have one original and a copy */ Iterator mIterator = mSimpleList.iterator(); // Now add an element to the orginal mSimpleList.add(400); // Now iterate using mIterator List<Integer> comp = new LinkedList<Integer>(); mIterator.forEachRemaining(comp::add); // Now check all elements. assertThat(comp).containsOnly(0,1,2); // it returns true, which means we were working on the copy /* * Any iterator that we obtain later will have 10 in it as a new copy will be created. * In contrast, we will always be working on the current copy if we were using an ArrayList. */
In conclusion, for thread-safe iteration in lists, you have the option to use CopyOnWriteArrayList.