You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Java forEach Lambda会抛出ConcurrentModificationException?

Why does this forEach-based method throw ConcurrentModificationException, but a regular for-loop works?

Great question—let’s unpack this. First off, your hunch about static methods and local variables is off the mark here: local variables like allocAccounts are thread-local, so they’re not the issue. The problem boils down to how Java’s collection forEach methods handle iteration, versus how indexed for-loops do it.

Let’s start with the forEach failure

Looking at your stack trace, the exception comes straight from ArrayList.forEach(). If you peek under the hood of ArrayList’s forEach implementation, it uses a fail-fast check:

public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    final E[] elementData = (E[]) this.elementData;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        action.accept(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

It takes a snapshot of the collection’s modification count (modCount) at the start of iteration. If any structural change (adding/removing elements) happens to the ArrayList while forEach is running, modCount increments. When the loop finishes, it compares the current modCount to the original—if they don’t match, it throws the exception to alert you to potential data inconsistency.

Even though you said each thread has its own Execution copy, there’s a likely catch: either execution.legs() or executionLeg.allocs() is returning a shared collection instance (maybe a shallow copy where the underlying list is still referenced across threads), or it’s a view of another shared collection that’s being modified mid-iteration. That’s what’s triggering the fail-fast check.

Why the regular for-loop doesn’t throw

Your indexed for-loop skips the fail-fast check entirely. It just grabs elements by index directly from the array backing the list. This avoids the exception, but it’s not actually solving the root thread-safety problem—you might still get inconsistent data (like missing elements or duplicates) if the collection is modified concurrently, it just won’t tell you about it.

Proper fixes to consider

If you want to eliminate the exception and ensure thread safety, here are your best bets:

  • Switch to thread-safe collections: Replace ArrayList with CopyOnWriteArrayList for the legs or allocs collections. This class makes a copy of the underlying array whenever a structural change happens, so iterators work on a stable snapshot and never throw ConcurrentModificationException.
  • Use deep copies: Make sure each thread’s Execution instance has fully independent copies of legs and allocs (not just shallow references). That way, modifications in one thread don’t affect others.
  • Synchronize access: If you can’t change the collection type, wrap both iteration and modification operations in synchronized blocks using a common lock. Just be aware this can hit performance if you have high concurrency.

内容的提问来源于stack exchange,提问作者Shashi Shankar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:29:29