|
| 1 | +Internal Working of CopyOnWriteArrayList in Java |
| 2 | + |
| 3 | +Introduction |
| 4 | +------------ |
| 5 | +- `CopyOnWriteArrayList` is a part of `java.util.concurrent` package. |
| 6 | +- It is a **thread-safe variant of ArrayList**. |
| 7 | +- Instead of synchronizing all operations, it uses a **copy-on-write strategy**: |
| 8 | + - Every time a modification (add, set, remove) is made, it creates a new copy of the underlying array. |
| 9 | + - Read operations (like get, iteration) are performed on the old immutable snapshot. |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +1. Underlying Data Structure |
| 14 | +---------------------------- |
| 15 | +- Internally, it uses a **volatile array of Objects**: |
| 16 | + |
| 17 | +private transient volatile Object[] array; |
| 18 | + |
| 19 | +- Reads always happen on this immutable snapshot. |
| 20 | +- Updates create a fresh copy, apply changes, and then replace the reference. |
| 21 | + |
| 22 | +--- |
| 23 | + |
| 24 | +2. How Modifications Work |
| 25 | +------------------------- |
| 26 | + |
| 27 | +👉 Example: add(E e) |
| 28 | +1. Lock is acquired (using ReentrantLock). |
| 29 | +2. Current array is copied into a new array. |
| 30 | +3. New element is added to the end. |
| 31 | +4. Reference of internal `array` is updated to the new one. |
| 32 | +5. Lock is released. |
| 33 | + |
| 34 | +👉 Example: remove(int index) |
| 35 | +1. Lock is acquired. |
| 36 | +2. A new array is created without the element at the index. |
| 37 | +3. Reference is updated. |
| 38 | +4. Lock is released. |
| 39 | + |
| 40 | +👉 Example: set(int index, E element) |
| 41 | +1. Lock is acquired. |
| 42 | +2. A new array is cloned. |
| 43 | +3. Element replaced at the index. |
| 44 | +4. Reference updated. |
| 45 | +5. Lock released. |
| 46 | + |
| 47 | +--- |
| 48 | + |
| 49 | +3. Read Operations |
| 50 | +------------------ |
| 51 | +- Reads (like `get()`, iteration) **don’t need a lock**. |
| 52 | +- They simply access the current `volatile` array. |
| 53 | +- Iterators are **fail-safe** (not fail-fast): |
| 54 | + - They iterate over the snapshot array that existed at the time of iterator creation. |
| 55 | + - So modifications made after iterator creation are not visible in iteration. |
| 56 | + |
| 57 | +--- |
| 58 | + |
| 59 | +4. ASCII Diagram — Copy on Write |
| 60 | + |
| 61 | +Initial: |
| 62 | +array = [A, B, C] |
| 63 | + |
| 64 | +Thread 1 → add(D) |
| 65 | +- Creates new array: [A, B, C, D] |
| 66 | +- Updates `array` reference. |
| 67 | + |
| 68 | +Meanwhile, Thread 2 (iterating): |
| 69 | +- Still sees old array: [A, B, C] |
| 70 | + |
| 71 | +--- |
| 72 | + |
| 73 | +5. Complexity Analysis |
| 74 | +---------------------- |
| 75 | +- get(index): O(1) (direct array access). |
| 76 | +- iteration: O(n), but **no ConcurrentModificationException**. |
| 77 | +- add/remove/set: O(n) because of array copying. |
| 78 | +- Memory overhead: High (creates new array on every modification). |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +6. Advantages |
| 83 | +------------- |
| 84 | +- Thread-safe without explicit synchronization for reads. |
| 85 | +- Iterators are safe even during concurrent modifications. |
| 86 | +- Great for **read-heavy, write-light** scenarios. |
| 87 | + |
| 88 | +--- |
| 89 | + |
| 90 | +7. Limitations |
| 91 | +-------------- |
| 92 | +- Expensive for write-heavy workloads (copy on every update). |
| 93 | +- Memory overhead increases with frequent modifications. |
| 94 | +- Not suitable when the dataset changes very frequently. |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +8. Example Code |
| 99 | +--------------- |
| 100 | + |
| 101 | +import java.util.concurrent.CopyOnWriteArrayList; |
| 102 | + |
| 103 | +public class COWALDemo { |
| 104 | + public static void main(String[] args) { |
| 105 | + CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); |
| 106 | + |
| 107 | + list.add("A"); |
| 108 | + list.add("B"); |
| 109 | + list.add("C"); |
| 110 | + |
| 111 | + System.out.println("Initial list: " + list); |
| 112 | + |
| 113 | + // Iteration is over snapshot |
| 114 | + for (String s : list) { |
| 115 | + System.out.println("Iterating: " + s); |
| 116 | + list.add("D"); // No ConcurrentModificationException |
| 117 | + } |
| 118 | + |
| 119 | + System.out.println("After modification: " + list); |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +Output: |
| 124 | +Initial list: [A, B, C] |
| 125 | +Iterating: A |
| 126 | +Iterating: B |
| 127 | +Iterating: C |
| 128 | +After modification: [A, B, C, D, D, D] |
| 129 | + |
| 130 | +--- |
| 131 | + |
| 132 | +Summary |
| 133 | +---------- |
| 134 | +- CopyOnWriteArrayList is ideal when: |
| 135 | + - Reads are far more frequent than writes. |
| 136 | + - You need thread-safe iterations without synchronization overhead. |
| 137 | +- Internally: **copy on each write** → safe but costly for frequent modifications. |
| 138 | +- Best for: Caches, observer lists, configuration data that rarely changes. |
0 commit comments