s iterator 循环map的理解 下面这个居然是死循环

如题,最近项目里有个模块我做了异步处理方面的事情,在code过程中发现一个颠覆我对synchronized这个关键字和用法的地方,请问各位java开发者们是否对此有一个合理的解释,不多说,我直接贴出问题代码:
(事实证明这是一个坑,各位读者,如果有兴趣,可以先不看答案,自己看看能不能发现这个坑)
import java.util.ArrayL
import java.util.C
import java.util.L
import java.util.concurrent.CopyOnWriteArrayL
public class ConcurrentList {
//private static List&String& TEST_LIST = new CopyOnWriteArrayList&String&();
private static List&String& TEST_LIST = Collections.synchronizedList(new ArrayList&String&());
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
while (true) {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (TEST_LIST) {
TEST_LIST.add("11");
System.out.println("Thread1 running");
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (TEST_LIST) {
for (String at : TEST_LIST) {
TEST_LIST.add("22");
System.out.println("Thread2 running");
}).start();
输出结果是:
Thread1 running
Exception in thread "Thread-1" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at com.free4lab.lol.ConcurrentList$2.run(ConcurrentList.java:40)
at java.lang.Thread.run(Thread.java:619)
Thread1 running
Thread1 running
Thread1 running
Thread1 running
Thread1 running
Thread1 running
Thread1 running
Thread1 running
-----------------------------------分隔线,以下是解释--------------------------------
问题明了了:
以上问题不是并发的问题,是ArrayList的问题,是个坑!且看如下代码,以及运行结果:
import java.util.ArrayL
import java.util.C
import java.util.L
import java.util.concurrent.CopyOnWriteArrayL
public class ConcurrentList {
//private static List&String& TEST_LIST = new CopyOnWriteArrayList&String&();
private static List&String& TEST_LIST = Collections.synchronizedList(new ArrayList&String&());
public static void main(String[] args) {
TEST_LIST.add("111");
TEST_LIST.add("222");
for (String at : TEST_LIST) {
System.out.println(at);
TEST_LIST.add("333");
System.out.println("add over");
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at com.free4lab.lol.ConcurrentList.main(ConcurrentList.java:15)
分析:我们发现迭代了一次之后就抛出所谓的并发修改异常,不过这里没有多线程,看下源代码就知道了
list.add的时候执行了,修改了modCount,循环外面一次add到第一次迭代不会有问题,因为初始化的时候在AbstractList中int expectedModCount = modC,
* Appends the specified element to the end of this list.
* @param e element to be appended to this list
* @return &tt&true&/tt& (as specified by {@link Collection#add})
public boolean add(E e) {
ensureCapacity(size + 1);
// Increments modCount!!
elementData[size++] =
return true;
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.
if (minCapacity & oldCapacity) {
Object oldData[] = elementD
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity & minCapacity)
newCapacity = minC
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
public E next() {
checkForComodification();
E next = get(cursor);
lastRet = cursor++;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
这样迭代器next()第一次&checkForComodification() 是不会抛出异常的,第二次才会抛出异常,因为在checkForComodification()里检查了
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
这样,在循环迭代中,进行了一次add操作,修改了modcount变量,再次迭代的时候,异常就throw出来了!
如果非要进行这样的操作,那么声明list为CopyOnWriteArrayList,就ok!因为用了copyonwrite技术
import java.util.ArrayL
import java.util.C
import java.util.L
import java.util.concurrent.CopyOnWriteArrayL
public class ConcurrentList {
private static List&String& TEST_LIST = new CopyOnWriteArrayList&String&();
//private static List&String& TEST_LIST = Collections.synchronizedList(new ArrayList&String&());
public static void main(String[] args) {
TEST_LIST.add("111");
TEST_LIST.add("222");
for (String at : TEST_LIST) {
System.out.println(at);
TEST_LIST.add("333");
System.out.println("add over");
输出是正确的:
额外再说一点,也可以用iterator迭代,不过同样也无法调用next()方法(我注释掉了),这样程序就是死循环了,不断的加,不断的迭代。所以我感觉如果需要在迭代中增加元素,真正有用的还是CopyOnWriteArrayList,不过实际中,如果CopyOnWriteArrayList代价太高,可能我们可以申请一个临时list存放,在迭代后合并到主list中!
import java.util.ArrayL
import java.util.C
import java.util.I
import java.util.L
import java.util.concurrent.CopyOnWriteArrayL
public class ConcurrentList {
//private static List&String& TEST_LIST = new CopyOnWriteArrayList&String&();
private static List&String& TEST_LIST = Collections.synchronizedList(new ArrayList&String&());
public static void main(String[] args) {
TEST_LIST.add("111");
TEST_LIST.add("222");
Iterator iterator
= TEST_LIST.iterator();
while(iterator.hasNext()){
//System.out.println(iterator.next());
TEST_LIST.add("333");
System.out.println("add over");
阅读(...) 评论()查看: 5409|回复: 16
iterator的死循环。
论坛徽章:1
问题原来描述不是很清楚,重新写一下:
1. 这段代码在it++处会死循环:(VC6, g++)
std::set&int&
std::set::iterator&int&
it = what.begin();
2. 这段代码则运行正常。(VC6, g++)
std::set&int&
std::set::iterator&int&
waht.insert(0);
it = what.begin();
一般不会这么使用,但是如果极少情况下这样使用还是存在的,问题是,如果前一种情况会铁定造成死循环,那么哥势必必须每次这样使用的时候都必须判断下set是不是为空。
[I]============================================
std::set::
what.insert(1);
it = what.end();
it++++++++;
what.begin()-----------------------------------------;
what.insert(1);&&如果没有这一句,也就是what是空的set,it++++++++++++或者it-----------------都会造成死循环,一个++/--也是一样的,STL内部的死循环。
哥不明白,it++为什么要死循环,难道哥每次都要判断下set是不是空啊?
刚开始怀疑是VC6的问题,结果在Ubuntu下g++编译,效果完全一样。[/I]
[ 本帖最后由 低碳马甲 于
21:02 编辑 ]
论坛徽章:377
文档上怎么写的?
论坛徽章:30
如果允许你it+++++++...这样不停加下去,实现时就需要自动将不存在的下标填值,size也自动不断加大
问题是set是不允许重复元素的,那应该填什么默认值,你告诉我
map是可以这样的,如果你用map[不存在的下标]来访问,map会帮你新增一个元素
论坛徽章:30
map因为不存在重复的问题,所认新分配的内存原来是什么就是什么
如果set按map的方式肯定会出问题,所以如果按你的想法自动新增元素,就要检查该元素是否存在,存在还要帮你生造一个不存在的元素插入
如果我是stl的实现者,你提出这样的需求,我会一巴掌拍飞你
这还是c++吗
论坛徽章:3
和实现有关,可能不能这样用
论坛徽章:1088
原帖由 mwjx 于
17:38 发表
map因为不存在重复的问题,所认新分配的内存原来是什么就是什么
如果set按map的方式肯定会出问题,所以如果按你的想法自动新增元素,就要检查该元素是否存在,存在还要帮你生造一个不存在的元素插入
如果我是stl的实现者,你提出这样的需求,我会一巴掌拍飞你
这还是c++吗
嘿嘿,所言甚至,list也没有这样的问题,还是看stl源代码实现
论坛徽章:1
原帖由 mwjx 于
17:32 发表
如果允许你it+++++++...这样不停加下去,实现时就需要自动将不存在的下标填值,size也自动不断加大
问题是set是不允许重复元素的,那应该填什么默认值,你告诉我
map是可以这样的,如果你用map[不存在的下标]来访问,map会帮你新增一个元素
不对,it是独立于what,很类似于一个指针,核心是保留指向set里面的一个节点,如果set为空,那么begin和end返回的it应该用某种形式表示其指向一个无效的节点。那么一个无效的节点--/++,无论多少次,还是指向一个无效的节点。这点和set里面有没有内容应该是完全一致的。但是事实的情况是,如果set有内容,无论你++/--多少次都不会出问题,但是set为空,++/--一次就出错了。
论坛徽章:1
原帖由 mwjx 于
17:38 发表
map因为不存在重复的问题,所认新分配的内存原来是什么就是什么
如果set按map的方式肯定会出问题,所以如果按你的想法自动新增元素,就要检查该元素是否存在,存在还要帮你生造一个不存在的元素插入
如果我是stl的实现者,你提出这样的需求,我会一巴掌拍飞你
这还是c++吗
老大,很严重,你用过stl没有?
论坛徽章:52
需搞清下面两个问题,自然就清楚1楼的原因了。
i++++++++;
int arr[100];
p++++++++;
论坛徽章:1
原帖由 bodyguard 于
20:27 发表
需搞清下面两个问题,自然就清楚1楼的原因了。
i++++++++;
int arr[100];
p++++++++;
又扯蛋了不是?风马牛不相及
itpub.net All Right Reserved. 北京皓辰网域网络信息技术有限公司版权所有    
 北京市公安局海淀分局网监中心备案编号: 广播电视节目制作经营许可证:编号(京)字第1149号java我的迭代器程序为什么会出现死循环?_百度知道
java我的迭代器程序为什么会出现死循环?
List list = new ArrayList();
list.add(&aaa&);
list.add(&bbb&);Iterator ite = list.iterator();
缉礌光啡叱独癸扫含激
while(ite.hasNext()){
System.out.println(“------”);}
提问者采纳
加上这句:String s = (String)ite.next();因为你已经添加了元素所以缉礌光啡叱独癸扫含激ite.hasNext()的值一直是true当然是死循环了。
提问者评价
非常感谢!!!
其他类似问题
为您推荐:
其他3条回答
当然会出现死循环原因:你没有使用next()方法,就是返回下一个元素,所以你 的程序中的游标(迭代器)始终停留在了aaa的前面,而没有跳到下一个位置,因为ite.hasNext()) 只是判断是否有下一个元素,而 String str = (String) ite.next()才是缉礌光啡叱独癸扫含激返回下一个元素并将游标(迭代器)移动到下一个元素的位置
ite一直都有next。。。。你需要移动“next”。。。具体的 zskzhao 已经说了。我就不抢分了。
学到了 ,还没注意过这种情况
迭代器的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁java 中这句什么意思?_百度知道
java 中这句什么意思?
public class CoffeeGeneratorimplements Generator&lt.println(c)Coffee&
public CoffeeGenerator(int sz) { size = sz, M&#47: new CoffeeGenerator(5))
System.println(gen.
public static void main(String[] args) {
CoffeeGenerator gen = new CoffeeGenerator(); }
public Coffee next() {
count--; {
private Class[] types = { L
class CoffeeIterator implements Iterator&&#47.*;
public boolean hasNext() { return count & 5:
} catch(Exception e) {
throw new RuntimeException(e);/
private static Random rand = new Random(47);
public Iterator&lt:
private int size = 0.newInstance(), Breve.class.
return CoffeeG
for(C F iterator() {
return new CoffeeIterator();
&#47, }.Coffee& }
public Coffee next() {
return (Coffee)
types[rand.next());Coffee&gt.
public CoffeeGenerator() {}
/&#47, Iterable&?然后一直减减都没执行其他东西
public void remove() { &#47. i &lt.next();Coffee& i++)
S 0,感觉这样调用不是一直调用next() 吗.
for(int i = 0.length)]; {
int count = size,
Cappuccino.util, A Not implemented
throw new UnsupportedOperationException();/这句.class.*; Report programmer errors at run time.nextInt(types.out.import java
提问者采纳
public Coffee next() {
count--?然后一直减减都没执行其他东西
}这样的代码岂不是要落入死循环中;
return CoffeeGenerator.迭代器的落脚点在于currentIndex&nbsp?//&nbsp.next();//这句,感觉这样调用不是一直调用next() 吗;和&nbsp//&个人觉得next()方法有问题
话说我也这么认为。但其实不是,能运行的不会死循环
提问者评价
其他类似问题
为您推荐:
其他1条回答
这个方法实现的是Iterator接口,是个迭代器,实质是遍历了一遍CoffeeGenerator
您可能关注的推广
java的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁

我要回帖

更多关于 iterator for 循环 的文章

 

随机推荐