Avoiding ConcurrentModificationException on List by making a shallow copy

泪湿孤枕 提交于 2020-01-23 07:01:51

问题


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?


回答1:


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.




回答2:


That's because you are returning a copy of the List rather than the list itself. remove() is the only method which is modifying the actual list, accessible by multiple threads. Threads calling the getAllPersons() method will anyways getting a new list, so if they modify this list, its not going to change the original list. So as your collection is not getting modified concurrently by threads you are not getting ConcurrentModificationException.



来源:https://stackoverflow.com/questions/7169913/avoiding-concurrentmodificationexception-on-list-by-making-a-shallow-copy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!