multithreadingjava-8copyonwritearraylist

CopyOnWriteArrayList is not working as expected


I am learning on CopyOnWriteArrayList and its not working as per my understanding. I have two threads, one is main thread and another is inner thread. Main thread is removing the objects from the CopyOnWriteArrayList collection while inner thread is sleeping for 5 seconds. Main thread is completing the remove operations much before inner thread is iterating but inner thread is still iterating the full collection, I mean which are removed by main thread.

package com.kalavakuri.javaconcurrent;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class ConcurrentModificationExceptionExample {

    private static List<String> strings = new CopyOnWriteArrayList<String>();

    public static void main(String[] args) {

        strings.add("Ram");
        strings.add("Ravi");
        strings.add("Raju");
        strings.add("Raghu1");
        strings.add("Raghu2");
        strings.add("Raghu3");
        strings.add("Raghu4");
        strings.add("Raghu5");
        strings.add("Raghu6");

        Thread thread = new Thread(() -> {
            Iterator<String> iterator = strings.iterator();
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
                System.out.println("Thread name " + Thread.currentThread().getName());
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Inner thread");

        thread.start();

        Iterator<String> iterator = strings.iterator();
        while (iterator.hasNext()) {
            String value = iterator.next();
            strings.remove(value);
            System.out.println("Thread name " + Thread.currentThread().getName());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        strings.forEach(v -> System.out.println(v));

    }
}

I am expecting that inner thread should not iterate the objects which are removed by main thread. Correct me if my understanding is wrong.


Solution

  • Yes, you are wrong. From the docs:

    The "snapshot" style iterator method uses a reference to the state of the array at the point that the iterator was created. This array never changes during the lifetime of the iterator, so interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException.

    So by design the iterator will not change when the other thread makes changes.