[英]ConcurrentModificationException when iterate through ImmutableMap.copyof()
Currently, I have a problem when I frequently iterating through a HashMap (1-time per second)目前,我在频繁迭代 HashMap 时遇到问题(每秒 1 次)
I add new element to the map on the main thread and iterate the map on the other thread我在主线程上向地图添加新元素并在另一个线程上迭代地图
I return an ImmutableMap.copyOf() to iterate through it, and sometimes I add a new element to the map.我返回一个 ImmutableMap.copyOf() 来遍历它,有时我会向地图添加一个新元素。 But it throws me a ConcurrentModificationException
但它给我一个 ConcurrentModificationException
java.util.ConcurrentModificationException: null
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911) ~[?:1.8.0_261]
at java.util.ArrayList$Itr.next(ArrayList.java:861) ~[?:1.8.0_261]
My pseudo-code:我的伪代码:
class Foo {
private final Map<String, List<User>> userMap = new HashMap<>();
public static void addUser(String houseId, User user) {
if(!userMap.containsKey(houseId)) {
userMap.put(houseId, new ArrayList<>());
}
List<User> list = userMap.get(houseId);
list.add(user);
}
public static Map<String, List<User>> getAll() {
return ImmutableMap.copyOf(userMap);
}
}
// iterating task
// this task run one per second
class Task extends TimerTask {
public void run() {
for (List<User> listUser : Foo.getAll().values()) {
for (User user : listUser) {
user.sayHello(); // print hello
}
}
}
}
I thought that use an ImmutableMap.copyOf() will prevent me from this problem.我认为使用 ImmutableMap.copyOf() 会阻止我解决这个问题。 Because I read that you should use an immutable copy of your list/map when iterating through it from other thread.
因为我读到您应该在从其他线程迭代时使用列表/地图的不可变副本。
I think I "solve" this by using CopyOnWriteArrayList.我想我通过使用 CopyOnWriteArrayList 来“解决”这个问题。 But I'm really curious why it throws me an error.
但我真的很好奇为什么它会给我一个错误。
Thank you!!!谢谢!!!
As you can see in the stack trace, the error occurs in the ArrayList, not the Map.正如您在堆栈跟踪中看到的,错误发生在 ArrayList 中,而不是 Map 中。 In method
addUser
, an element is added to the list via list.add(user);
在
addUser
方法中,一个元素通过list.add(user);
添加到列表中list.add(user);
This operation might happen, while another thread loops over the elements with for (User user : listUser)
causing the error.此操作可能会发生,而另一个线程使用
for (User user : listUser)
循环遍历元素,导致错误。
When you exchange the ArrayList with a CopyOnWriteArrayList, the list.add(user)
internally makes a copy and adds the new user into the copy.当您将 ArrayList 与 CopyOnWriteArrayList 交换时,
list.add(user)
内部创建一个副本并将新用户添加到副本中。 Therefore, a potentially running iteration is not affected since it loops over the old version of the array.因此,潜在的运行迭代不会受到影响,因为它会遍历数组的旧版本。 So the running iteration will ignore the new value.
所以运行迭代将忽略新值。 Any new iterator will include the new value.
任何新的迭代器都将包含新值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.