- 浏览: 211259 次
- 性别:
- 来自: 河北
文章分类
最新评论
-
6420285:
你的文章很棒,很多地方讲的通俗易懂,非常感谢。 ...
深入掌握JMS(一):JSM基础 -
xs.cctv:
不错
zeroDateTimeBehavior=convertToNull -
hanyannan0123:
搞不清楚,此话属于经典呢,还是废话。
超类 好 -
czy584521:
```我肯定他用了谷歌金山词霸
IBM的面试官被我忽悠蒙了 -
yuantong:
老板跳槽?什么概念
我们老板跳槽了 !!!
jdk5.0以上的for-each也是利用内部的iterator来遍历集合的(跟以前的iterator一样)获得的Iterator是一个内部类产生的迭代器,这个迭代器在调用next方法时,会检查列表是否被修改过,如果被修改过,就会抛出ConcurrentModificationException异常。进一步说,当使用 fail-fast iterator 对 Collection 或 Map 进行迭代操作过程中尝试直接修改 Collection / Map 的内容时,即使是在单线程下运行,java.util.ConcurrentModificationException 异常也将被抛出。Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。 所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
有意思的是如果你的 Collection / Map 对象实际只有一个元素的时候, ConcurrentModificationException 异常并不会被抛出。这也就是为什么在 javadoc 里面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
解决方法:在Map或者Collection的时候,不要用它们的API直接修改集合的内容,如果要修改可以用Iterator的remove()方法
由于for-each的写法,使我们无法获得iterator对象,所以这种遍历方式不能进行删除操作。只好改成了比较土的方法实现了,如下:
for (Iterator it = desk.getPkers().iterator(); it.hasNext();) {
PKer pkerOnDesk =(PKer) it.next();
it.remove();
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()方法。
发表评论
-
黑马程序员_java08_多线程
2016-03-13 13:01 446转载于:http://www.itxuexiwang.com/ ... -
Redis数据库的安装配置方
2016-02-23 11:27 795转载于:http://www.itxuexiwang.com/ ... -
通过 Redis 实现 RPC 远程方法调用(支持多种编程语
2016-02-23 11:27 846转载于:http://www.itxuexiwang.com/ ... -
CentOS Linux系统下安装Redis过程和配置参数说明
2016-02-28 18:39 604转载于:http://www.itxuexiwang.com/ ... -
64位Windows下安装Redis教程
2016-03-10 14:06 719转载于:http://www.itxuexiwang.com/ ... -
让Redis在你的系统中发挥更大作用的几点建议
2016-03-10 14:06 1006转载于:http://www.itxuexiw ... -
Redis主从复制问题和扩容问题的解决思路
2016-02-25 13:26 1002转载于:http://www.itxuexiw ... -
超强、超详细Redis数据库入门教程
2016-02-28 18:39 575转载于:http://www.itxuexiw ... -
Redis总结笔记(二):C#连接Redis简单例子
2016-02-26 17:24 729转载于:http://www.itxuexiwang.com/ ... -
redis启动流程介绍
2016-03-10 14:07 637转载于:http://www.itxuexiwang.com/ ... -
redis中使用java脚本实现分布式锁
2016-03-13 13:03 590转载于:http://www.itxuexiwang.com/ ... -
redis常用命令、常见错误、配置技巧等分享
2016-02-26 17:23 538转载于:http://www.itxuexiwang.com/ ... -
Redis数据库的使用场景介绍(避免误用Redis)
2016-03-11 12:12 549转载于:http://www.itxuexiw ... -
分割超大Redis数据库例子
2016-02-26 17:23 661转载于:http://www.itxuexiwang.com/ ... -
使用Redis实现用户积分排行榜的教程
2016-02-19 11:35 1020转载于:http://www.itxuexiwang.com/ ... -
Redis教程(九):主从复制配置实例
2016-02-19 11:35 810转载于:http://www.itxuexiwang.com/ ... -
Redis教程(十):持久化详解
2016-03-15 15:44 614转载于:http://www.itxuexiwang.com/ ... -
Redis教程(十二):服务器管理命令总结
2016-02-18 21:53 0转载于:http://www.itxuexiwang.com/ ... -
Redis教程(十二):服务器管理命令总结
2016-02-18 21:48 0转载于:http://www.itxuexiw ... -
REDIS GEO: REDIS新增位置查询功能
2016-02-18 21:20 714转载于:http://www.itxuexiw ...
相关推荐
Java.util.ConcurrentModificationException 异常问题详解 ConcurrentModificationException 异常是 Java 中一个常见的异常,它发生在 Iterator 遍历集合时,集合同时被修改引起的异常。在 Java 中,集合类如 ...
java.util.ConcurrentModificationException 解决方法 在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除。 则使用会报以下异常: Java.util....
在Java编程中,`java.util.ConcurrentModificationException` 是一个常见的运行时异常,通常发生在尝试并发修改集合时。这个异常的产生是由于集合类(如HashMap)的非线程安全特性,当你在一个线程中使用迭代器遍历...
- **注意事项**:使用`Vector`创建的迭代器时,如果其他线程修改了`Vector`的状态(如添加或删除元素),则可能会抛出`ConcurrentModificationException`异常。 #### 七、`Stack`类 `Stack`继承自`Vector`,实现了...
2. 使用Java 8的流(Stream)API,这提供了更简洁且线程安全的处理方式: ```java map.entrySet().stream() .filter(entry -> entry.getValue() > 10) .forEach(entry -> map.remove(entry.getKey())); ``` 3. ...
但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除元素),Iterator将抛出ConcurrentModificationException异常。 Set接口是Collection接口的子接口...
使用`synchronized`关键字、`volatile`变量、`java.util.concurrent`包中的工具类等可以有效地管理并发。 四、内存泄漏 Java中的内存泄漏并不像C++那样直接导致资源耗尽,但过度持有对象引用会导致垃圾收集器无法...
这意味着在多线程环境下,当一个线程正在遍历集合(通过迭代器进行)时,另一个线程修改了集合内容,就会触发快速失败(fail-fast)机制,导致ConcurrentModificationException异常。例如,上述代码中,线程在删除...
java.util.ConcurrentModificationException: mutation occurred during iteration [error] scala.collection.mutable.MutationTracker$.checkMutations(MutationTracker.scala:43) [error] scala.collection....
- `java.util.Iterator`的改进:支持`remove()`操作,避免抛出`ConcurrentModificationException`。 ### 4. 性能优化 JDK 1.6对编译器和垃圾收集器进行了优化,提高了运行效率,例如: - **Server VM的改进**: ...
在Java编程的世界里,迭代是处理集合数据的重要手段之一。本文将重点探讨两种常用的迭代方式——`Iterator`接口和`Enhanced for loop`(增强型for循环),并从多个角度对比分析它们的特点、应用场景以及使用技巧。 ...
- `CopyOnWriteArrayList`和`CopyOnWriteArraySet`:这些列表和集在线程安全的迭代器上有优势,因为它们在修改时复制底层数组,从而避免了迭代过程中的并发修改异常(`ConcurrentModificationException`)。...
在Java编程语言中,集合框架(`java.util`包)提供了多种容器类来存储对象,如`List`、`Set`和`Map`等。为了遍历这些容器中的元素,Java引入了迭代器模式(Iterator Pattern),这是一种常用的设计模式,它提供了一...
11. **NullPointerException**和**NullPointerException**:这两种异常在多线程编程中尤为常见,由于并发访问共享资源可能导致数据不一致,因此应使用`synchronized`关键字或`java.util.concurrent`包中的工具来管理...
Java并发包,也被称为`java.concurrent`包,是Java编程语言中处理多线程和并发操作的核心工具包。它提供了一系列高效、线程安全的类和接口,使得开发者能够更安全、更容易地编写多线程应用程序。这个压缩包`...
5. **异常处理** 在使用`Iterator`时,需要特别注意以下两种可能抛出的异常: - `NoSuchElementException`: 当尝试访问不存在的下一个元素时抛出。 - `ConcurrentModificationException`: 如果在迭代过程中,集合...
`java.util.concurrent.ForkJoinPool`和`java.util.concurrent.RecursiveTask`是其核心类。 7. **非阻塞堆栈跟踪(Non-blocking Stack Traces)** 当线程处于等待状态时,Java 7可以生成不包含阻塞信息的堆栈跟踪...
Fail-fast机制是一种快速失败机制,在集合遍历过程中,一旦发现容器中的数据被修改了,会立刻抛出ConcurrentModificationException异常,从而导致遍历失败。这种机制下的集合容器,例如HashMap和ArrayList等,都是...