Java中重写LinkedList迭代器时如何检测并发修改异常?
在自定义双向链表迭代器中实现并发修改异常检测
要在自定义迭代器中检测并发修改异常,核心是使用fail-fast机制——通过维护「链表修改计数器」和「迭代器预期修改计数器」的配对关系来实现,这也是Java标准集合(如ArrayList、LinkedList)的通用做法。
具体实现步骤:
在双向链表类中添加修改计数器
在链表类中声明一个modCount成员变量,每次执行会改变链表结构的操作(比如add、remove、clear)时,将modCount自增,记录链表被修改的次数。在迭代器中维护预期修改计数器
创建迭代器时,将内部的expectedModCount初始化为当前链表的modCount值,相当于保存一份迭代器创建时的链表修改状态快照。每次迭代操作前检查计数器一致性
在迭代器的next()、hasNext()方法中,先检查modCount和expectedModCount是否相等。如果不等,说明迭代器创建后链表被外部线程或其他迭代器修改了,直接抛出ConcurrentModificationException。迭代器自身修改时同步计数器
如果迭代器实现了remove()方法(合法的迭代器内修改),执行完移除操作后,需要同步更新modCount和expectedModCount,避免触发异常。
修改后的完整代码示例
双向链表类核心部分
public class DoublyLinkedList<T> { private Node<T> head; private Node<T> tail; // 记录链表结构修改次数的计数器 private int modCount = 0; // 示例:添加元素的方法,每次修改结构后自增modCount public void add(T data) { Node<T> newNode = new Node<>(data); if (head == null) { head = newNode; tail = newNode; } else { tail.next = newNode; newNode.prev = tail; tail = newNode; } modCount++; // 结构修改,计数器自增 } // 示例:移除元素的方法,同样需要自增modCount public boolean remove(T data) { Node<T> current = head; while (current != null) { if (data.equals(current.data)) { if (current.prev != null) { current.prev.next = current.next; } else { head = current.next; } if (current.next != null) { current.next.prev = current.prev; } else { tail = current.prev; } modCount++; return true; } current = current.next; } return false; } // 内部节点类 private static class Node<T> { T data; Node<T> prev; Node<T> next; Node(T data) { this.data = data; } } // 重写的iterator方法,包含并发检测逻辑 @Override public Iterator<T> iterator() { return new Iterator<T>() { private Node<T> trav = head; // 初始化预期修改计数器为当前链表的modCount private int expectedModCount = modCount; @Override public boolean hasNext() { checkForComodification(); return trav != null; } @Override public T next() { checkForComodification(); if (!hasNext()) { throw new NoSuchElementException(); } T data = trav.data; trav = trav.next; return data; } // 可选:实现迭代器的remove方法 @Override public void remove() { if (trav == head) { throw new IllegalStateException("无法移除未访问的元素"); } Node<T> toRemove = trav.prev; if (toRemove.prev != null) { toRemove.prev.next = toRemove.next; } else { head = toRemove.next; } if (toRemove.next != null) { toRemove.next.prev = toRemove.prev; } else { tail = toRemove.prev; } // 同步计数器,避免触发异常 modCount++; expectedModCount = modCount; } // 检查并发修改的私有工具方法 private void checkForComodification() { if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } } }; } }
关键说明
- fail-fast的局限性:这种机制是一种快速检测手段,不能保证100%检测到所有并发修改(比如在多线程环境下的极端情况),但足以应对绝大多数单线程和常规多线程场景下的非安全修改。
- 合法修改的处理:只有迭代器自身的
remove()操作不会触发异常,其他外部修改(比如直接调用链表的add/remove)都会被检测到。
内容的提问来源于stack exchange,提问作者Anish
相关产品推荐
相关产品推荐

