我有一堂课如下:
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
可以同时修改:一个是viaremove()
由一个线程和两个通过返回的浅复制实例getAllPersons()
.
我在多线程环境中测试了上述场景,看看是否可以避免ConcurrentModificationException
通过返回一个浅拷贝getAllPersons()
叫做。这似乎有效。我从来没有遇到过ConcurrentModificationException
.
在这种情况下,为什么只制作一个浅拷贝persons
避免一个ConcurrentModificationException
?
当集合以导致打开迭代器无效的方式更改时,会引发 ConcurrentModificationException。当多个线程访问非线程安全的集合时,通常会发生这种情况(尽管这不是唯一的原因)
您的代码中仍然存在一个小错误 - 要安全地访问本身不是线程安全的成员,您应该synchronize
在 getAllPersons 方法上。
假设这是固定的——因为您要返回一个副本,所以集合本身不能被其他调用者修改(每个调用者都会获得他们自己的副本)。这意味着您永远不会得到 ConcurrentModificationException。
请注意,这does not保护您免受线程安全问题的影响Person
类,只有集合本身。如果Person
是不可变的,你应该没问题。
在这种情况下,更好的解决方案是直接使用写入数组列表时复制 http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html它实现了类似的语义,但仅在您实际写入列表时复制 - 而不是每次读取时复制。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)