【问题标题】:How to remove element from list safely如何安全地从列表中删除元素
【发布时间】:2021-09-16 03:29:09
【问题描述】:
for (Iterator<Long> it = ids.iterator(); it.hasNext(); ) {
    Long temp = it.next().longValue();
    if (oo.contains(temp)) {
        it.remove();
    }
}

我做对了吗?
如果我在单线程和多线程环境中都使用迭代器 remove(), 我不会得到任何ConcurrentModificationException 或其他异常吗?

【问题讨论】:

  • 不,Iterator.remove 不是消除所有 CME 的灵丹妙药。
  • 调用#longValue() 是不必要的。
  • 请注意,投掷CME的地方并不是真正的违规地方。这是一个额外的检查,用于检测是否有一些违规代码在不久之前执行(通常是多线程的,但不一定)。

标签: java for-loop iterator


【解决方案1】:

如果我在单线程和多线程环境中都使用迭代器 remove(),我会不会得到任何 ConcurrentModificationException 或其他一些异常?

一般来说,对于单线程和多线程环境,您都会收到ConcurrentModificationExceptions。

CME 可能由很多原因引起,而不仅仅是“在使用迭代器迭代列表时不使用 Iterator.remove”。例如,下面是一些产生 CME 的代码:

List<String> list = new ArrayList<>(List.of("1", "2"));
Iterator<String> iter = list.iterator();
iter.next();
list.add(0, "first!"); // adding to the list while iterating over it
iter.remove(); // we're using Iterator.remove here, still CME!

还有,

List<String> list = new ArrayList<>(List.of("1", "2"));
// make two iterators of the same list
Iterator<String> iter1 = list.iterator();
Iterator<String> iter2 = list.iterator();
iter1.next(); // advance one of them
iter1.remove(); // we're using Iterator.remove here
iter2.next(); // iter2 doesn't know about iter1 has removed an element, so CME

问题中发生了类似的事情:Why does this Java code trigger a ConcurrentModificationException? 我已经回答了。

但在你的代码中,我没有看到这样的事情发生,所以我认为在单个线程中应该没问题。

但是,如果该列表可由多个线程访问,那么您就有问题了。 Iterator.remove 不应该为您解决所有多线程同步问题。如果您没有进行适当的同步,那么另一个线程可以在您迭代列表时对列表进行任何结构更改,也就是说。解决此问题的一种方法(根据您的用例肯定有更好的方法)是在对列表进行任何结构更改之前和迭代之前获取锁。

标准库提供了一堆线程安全的集合。 Choose the appropriate one if you need.

【讨论】:

  • 感谢很多帮助
  • @Greg 如果您认为我的回答回答了您的问题,请考虑通过单击该复选标记接受它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-15
  • 2021-03-10
  • 2010-10-13
  • 2014-05-06
  • 1970-01-01
  • 2015-11-29
相关资源
最近更新 更多