Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can CopyOnWriteArrayList be thread-safe?

I've taken a look into OpenJDK source code of CopyOnWriteArrayList and it seems that all write operations are protected by the same lock and read operations are not protected at all. As I understand, under JMM all accesses to a variable (both read and write) should be protected by lock or reordering effects may occur.

For example, set(int, E) method contains these lines (under lock):

/* 1 */ int len = elements.length; /* 2 */ Object[] newElements = Arrays.copyOf(elements, len); /* 3 */ newElements[index] = element; /* 4 */ setArray(newElements); 

The get(int) method, on the other hand, only does return get(getArray(), index);.

In my understanding of JMM, this means that get may observe the array in an inconsistent state if statements 1-4 are reordered like 1-2(new)-4-2(copyOf)-3.

Do I understand JMM incorrectly or is there any other explanations on why CopyOnWriteArrayList is thread-safe?

like image 405
Fixpoint Avatar asked Jun 01 '10 15:06

Fixpoint


People also ask

Can we remove element from CopyOnWriteArrayList?

The remove(int index) method of CopyOnArrayList in Java is used to remove the element at the specified position in the list. Parameters: This method accepts a mandatory parameter index which specifies the position of the element. Return Type: This method returns the list after deleting the specified element.

Is CopyOnWriteArrayList concurrent?

CopyOnWriteArrayList is a concurrent Collection class introduced in Java 5 Concurrency API along with its popular cousin ConcurrentHashMap in Java.

What is difference between ArrayList and CopyOnWriteArrayList?

CopyOnWriteArrayList is synchronized. ArrayList is not thread safe. CopyOnWriteArrayList is thread safe. ArrayList iterator is fail-fast and ArrayList throws ConcurrentModificationException if concurrent modification happens during iteration.


2 Answers

If you look at the underlying array reference you'll see it's marked as volatile. When a write operation occurs (such as in the above extract) this volatile reference is only updated in the final statement via setArray. Up until this point any read operations will return elements from the old copy of the array.

The important point is that the array update is an atomic operation and hence reads will always see the array in a consistent state.

The advantage of only taking out a lock for write operations is improved throughput for reads: This is because write operations for a CopyOnWriteArrayList can potentially be very slow as they involve copying the entire list.

like image 54
Adamski Avatar answered Nov 03 '22 00:11

Adamski


Getting the array reference is an atomic operation. So, readers will either see the old array or the new array - either way the state is consistent. (set(int,E) computes the new array contents before setting the reference, so the array is consistent when the asignment is made.)

The array reference itself is marked as volatile so that readers do not need to use a lock to see changes to the referenced array. (EDIT: Also, volatile guarantees that the assignment is not re-ordered, which would lead to the assignment being done when the array is possibly in an inconsistent state.)

The write lock is required to prevent concurrent modification, which may result the array holding inconsistent data or changes being lost.

like image 41
mdma Avatar answered Nov 02 '22 23:11

mdma