Search code examples
javalistshallow-copyconcurrentmodification

Avoiding ConcurrentModificationException on List by making a shallow copy


I have a class like the following:

class Test
{
    private LinkedList<Person> persons = new LinkedList<Person>;

    public synchronized void remove(Person person)
    {
        persons.remove(person);
    }

    public List<Person> getAllPersons()
    {
        // Clients may iterate over the copy returned and modify the structure.
        return new ArrayList<Person>(persons);
    }
}

persons may be modified concurrently: one is via remove() by one thread and two via the shallow copied instance returned by getAllPersons().

I have tested the above scenario in a multithreaded environment to see if I can avoid ConcurrentModificationException by returning a shallow copy when getAllPersons() is called. It seemed to work. I have never once encountered a ConcurrentModificationException.

Why, in this case, does making only a shallow copy of persons avoid a ConcurrentModificationException?


Solution

  • A ConcurrentModificationException is thrown when a collection changes in a manner which invalidates open iterators. This usually happens when a collection which is not thread safe is accessed by multiple threads (although this is not the only cause)

    There is still a small error in your code - to safely access a member which is not itself thread safe, you should synchronize on the getAllPersons method.

    Assuming that is fixed -- because you are returning a copy, the collection itself cannot be modified by other callers (each gets their own copy). That means that you can never get a ConcurrentModificationException.

    Note that this does not protect you against thread safety issues with your Person class, only the collections themselves. If Person is immutable, you should be OK.

    In this case, a better solution would be to directly use a CopyOnWriteArrayList which implements similar semantics, but only copies when you actually write to the list - not every time you read from it.