Java 通过创建浅拷贝避免列表上的ConcurrentModificationException
我的课程如下:Java 通过创建浅拷贝避免列表上的ConcurrentModificationException,java,list,shallow-copy,concurrentmodification,Java,List,Shallow Copy,Concurrentmodification,我的课程如下: class Test { private LinkedList<Person> persons = new LinkedList<Person>; public synchronized void remove(Person person) { persons.remove(person); } public List<Person> getAllPersons() {
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);
}
}
类测试
{
私人LinkedList人员=新LinkedList;
公共同步作废删除(人)
{
人。移除(人);
}
公共列表getAllPersons()
{
//客户端可以迭代返回的副本并修改结构。
返回新的ArrayList(人);
}
}
persons
可以同时修改:一个线程通过remove()
执行,两个线程通过getAllPersons()返回的浅复制实例执行
我已经在多线程环境中测试了上述场景,以查看在调用getAllPersons()
时是否可以通过返回浅层副本来避免ConcurrentModificationException
。这似乎奏效了。我从未遇到过ConcurrentModificationException
在这种情况下,为什么只创建人员的浅层副本可以避免ConcurrentModificationException
?当集合以使打开的迭代器无效的方式更改时,会引发ConcurrentModificationException。这通常发生在多个线程访问非线程安全的集合时(尽管这不是唯一原因)
代码中仍然有一个小错误-要安全地访问本身不是线程安全的成员,您应该在getAllPersons方法上进行同步
假设这是固定的——因为您要返回一个副本,所以集合本身不能被其他调用方修改(每个调用方都有自己的副本)。这意味着您永远无法获得ConcurrentModificationException
请注意,此不会保护您的Person
类的线程安全问题,仅保护集合本身。如果Person
是不可变的,您应该可以
在这种情况下,更好的解决方案是直接使用实现类似语义的,但仅在实际写入列表时进行复制,而不是每次读取列表时进行复制。这是因为返回的是列表的副本,而不是列表本身remove()
是修改实际列表的唯一方法,可由多个线程访问。调用getAllPersons()
方法的线程无论如何都会得到一个新列表,因此如果它们修改此列表,则不会更改原始列表。
因此,由于您的集合没有被线程同时修改,因此您也没有得到ConcurrentModificationException 除非他使用的是CopyOnReadArrayList!