出错原因不是由线程造成的,通过如下方式
java 代码
- Iterator it = myCollection.iterator();
获得的Iterator是一个内部类产生的迭代器,这个迭代器在调用next方法时,会检查列表是否被修改过,如果被修改过,就会抛出ConcurrentModificationException
异常
这个内部类在 java.util.AbstractList.java文件中有定义:
java 代码
- private
class
Itr
implements
Iterator<E> {
-
-
-
- int
cursor =
0
;
-
-
-
-
-
-
- int
lastRet = -
1
;
-
-
-
-
-
-
- int
expectedModCount = modCount;
-
- public
boolean
hasNext() {
- return
cursor != size();
- }
-
- public
E next() {
- checkForComodification();
- try
{
- E next = get(cursor);
- lastRet = cursor++;
- return
next;
- } catch
(IndexOutOfBoundsException e) {
- checkForComodification();
- throw
new
NoSuchElementException();
- }
- }
-
- public
void
remove() {
- if
(lastRet == -
1
)
- throw
new
IllegalStateException();
- checkForComodification();
-
- try
{
- AbstractList.this
.remove(lastRet);
- if
(lastRet < cursor)
- cursor--;
- lastRet = -1
;
- expectedModCount = modCount;
- } catch
(IndexOutOfBoundsException e) {
- throw
new
ConcurrentModificationException
();
- }
- }
-
- final
void
checkForComodification() {
- if
(modCount != expectedModCount)
- throw
new
ConcurrentModificationException
();
- }
- }
工作中碰到个ConcurrentModificationException。代码如下:
List list = ...;
for(Iterator iter = list.iterator(); iter.hasNext();) {
Object obj = iter.next();
...
if(***) {
list.remove(obj);
}
}
在执行了remove方法之后,再去执行循环,iter.next()的时候,报java.util.ConcurrentModificationException(当然,如果remove的是最后一条,就不会再去执行next()操作了)
下面来看一下源码
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
public interface Collection<E> extends Iterable<E> {
...
Iterator<E> iterator();
boolean add(E o);
boolean remove(Object o);
...
}
这里有两个remove方法
接下来来看看AbstractList
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//AbstractCollection和List都继承了Collection
protected transient int modCount = 0;
private class Itr implements Iterator<E> { //内部类Itr
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification(); //特别注意这个方法
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet); //执行remove对象的操作
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount; //重新设置了expectedModCount的值,避免了ConcurrentModificationException的产生
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount) //当expectedModCount和modCount不相等时,就抛出ConcurrentModificationException
throw new ConcurrentModificationException();
}
}
}
remove(Object o)在ArrayList中实现如下:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++; //只增加了modCount
....
}
所以,产生ConcurrentModificationException的原因就是:
执行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后当代码执行到next()方法时,判断了checkForComodification(),发现两个数值不等,就抛出了该Exception。
要避免这个Exception,就应该使用remove()方法。
这里我们就不看add(Object o)方法了,也是同样的原因,但没有对应的add()方法。一般嘛,就另建一个List了
下面是网上的其他解释,更能从本质上解释原因:
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator
被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭
代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出
java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
分享到:
相关推荐
在Java编程中,`iterator()`方法是集合框架中非常关键的一部分,主要用于遍历集合中的元素。当你遇到“方法iterator()找不着的问题”时,这通常意味着你在尝试使用`iterator()`时遇到了错误,可能是由于以下几个原因...
例如,可以定义一个字段来存储导致异常的具体原因,或者提供一个方法来获取详细的错误消息。 3. 在代码中,当遇到特定的错误条件时,通过`throw new 自定义异常类(错误信息)`来抛出自定义异常。这样,调用者可以...
- **异常处理:** Java强制要求捕获或声明抛出异常,而C++则允许程序员决定是否使用异常处理机制。 - **标准库:** Java的类库更加庞大和丰富,提供了更多的工具和框架支持。 - **安全性:** Java内置了更多的安全机制...
以下是一些主要的知识点: 1. **单元测试数据处理**: - 测试数据应加特殊前缀标识,以便区分于生产数据。 - 测试数据应使用独立的测试库,避免污染主数据库。 - 单元测试产生的脏数据应自动回滚,确保测试环境...
使用Iterator的好处是它可以检测并处理并发修改异常(ConcurrentModificationException),这是在遍历集合时尝试修改集合的常见错误。以下是如何使用Iterator遍历ArrayList: ```java ArrayList<String> arrayList ...
ArrayList的主要方法包括: 1. `add(E element)`: 向列表末尾添加一个元素。 2. `add(int index, E element)`: 在指定位置插入元素。 3. `remove(int index)`: 删除指定位置的元素。 4. `get(int index)`: 返回指定...
- **POST**方法:用于向指定资源提交数据进行处理请求(如提交表单),不能被缓存,不保留在浏览器历史记录中,可能会改变服务器状态。 #### Interface与abstract类的区别 - **接口(Interface)**: 只能包含抽象...
- **问题**:可能导致`ConcurrentModificationException`异常。 - **解决方案**:使用迭代器的`remove()`方法安全地删除元素。 #### 48. HashSet如何保证元素唯一性 - **原理**:通过`hashCode()`和`equals()`方法...
《Java开发手册(嵩山版)灵魂15问》中提到的禁止使用Apache Beanutils进行属性复制的原因主要是性能和安全性的考虑。Apache BeanUtils提供了便捷的属性拷贝功能,但在大规模或高性能应用中,其效率相对较低。相比其他...
- **service()**:处理客户端请求,根据请求方法调用相应的方法(如doGet/doPost)。 - **destroy()**:销毁Servlet,只执行一次。 25. **请简述一下Ajax的原理及实现步骤** - Ajax(Asynchronous JavaScript and...
例如,可能是在遍历`Map`时没有正确地处理`Iterator`,导致并发修改异常(`ConcurrentModificationException`);或者是在查找或插入键值对时遇到了键的唯一性问题;也可能是性能问题,比如在大量数据上使用了不适合...
- **方法重写(Overriding)**:发生在继承关系中的两个类之间,子类重新定义父类中的方法,方法名、返回类型及参数列表必须完全相同。 - **方法重载(Overloading)**:发生在同一个类中,允许存在多个同名方法,但...
当多个线程同时访问一个集合时,如果一个线程修改了集合,而另一个线程正在进行迭代,则抛出`ConcurrentModificationException`异常。 **39. 说说Hashtable 与 HashMap 的区别** - **线程安全性**:`Hashtable`...
- `Hashtable`直接使用键的`hashCode()`方法来计算哈希值,而`HashMap`会进一步处理键的哈希码,通常会调用`hash(key.hashCode())`来计算哈希值。 - **空键与空值的支持**: - `Hashtable`不允许键或值为空,而`...
- 当多个线程并发访问集合时,如果其中一个线程修改了集合结构,则其他正在访问该集合的线程会抛出`ConcurrentModificationException`异常,这就是快速失败机制。 #### 十、确保集合不可被修改 - **方法**:可以...
在Java编程中,遍历并删除List集合是一个常见的操作,但在实际编程中,如果不使用正确的方法,可能会导致`java.util.ConcurrentModificationException`异常。本文主要针对这个面试题,详细讲解如何在遍历List的同时...
- **原因**:数据不一致的主要原因是数据冗余,即同一数据在数据库中存在多份拷贝。 - **解决方案**:通过实施数据完整性控制措施,比如唯一约束、外键约束等,来避免数据冗余,从而提高数据的一致性。 #### 知识点...
在Java编程语言中,集合框架是处理对象存储和操作的核心工具。面试中,关于Java集合的知识点涵盖了集合的分类、接口、实现类以及其内部的工作原理。以下是对这些知识点的详细解析: 1. Java集合框架的层次结构: -...