问题描述
我有一个类似于以下的课程:
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
可以同时修改:一个通过一个线程通过remove()
进行,另一个通过getAllPersons()
返回的浅表复制实例进行.
persons
may be modified concurrently: one is via remove()
by one thread and two via the shallow copied instance returned by getAllPersons()
.
我已经在多线程环境中测试了上述情况,以查看是否可以通过在调用getAllPersons()
时返回浅表副本来避免ConcurrentModificationException
.它似乎有效.我从未见过ConcurrentModificationException
.
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
.
在这种情况下,为什么仅制作persons
的浅表副本会避免ConcurrentModificationException
?
Why, in this case, does making only a shallow copy of persons
avoid a ConcurrentModificationException
?
推荐答案
当集合以使打开的迭代器无效的方式进行更改时,将引发ConcurrentModificationException.当多个线程访问了一个不是线程安全的集合时,通常会发生这种情况(尽管这不是唯一的原因)
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)
您的代码中仍然存在一个小错误-为了安全地访问本身不是线程安全的成员,您应该在getAllPersons方法上synchronize
.
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.
假定是固定的-因为您要返回一个副本,所以其他调用者无法修改集合本身(每个调用者都拥有自己的副本).这意味着您永远不会获得ConcurrentModificationException.
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.
请注意,这不能保护您免受Person
类的线程安全问题的侵害,只能保护集合本身.如果Person
是不可变的,则应该没问题.
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.
在这种情况下,更好的解决方案是直接使用 CopyOnWriteArrayList ,它实现了类似的语义,但仅在您实际写入列表时才进行复制-并非每次读取时都复制.
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.
这篇关于通过进行浅表复制来避免List上的ConcurrentModificationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!