list set集合remove() ConcurrentModificationException 原因

来源:互联网 发布:php 5.4.10.tar.gz 编辑:程序博客网 时间:2024/06/06 20:58

方法一、

        ArrayList<String> list = new ArrayList<String>();         
 list.add("one");         
 list.add("two");         
 list.add("two");        
 list.add("two");         
 list.add("two");                 
 for(int i=0;i<list.size();i++){                         
  if(list.get(i).equals("two")){                         
   list.remove(i);                 
  }        
 }        
  System.out.println(list);


执行结果

[one, two, two]

注意: 此种方法可以删除list的数据,但删除后list的数据会自动向前面移动,这样会导致执行的结果和想要达到的效果不一样。


方法二、

        ArrayList<String> list2 = new ArrayList<String>();         
  list2.add("one");         
  list2.add("two");         
  list2.add("two");         
  list2.add("two");         
  list2.add("two");         
  for(String s:list2){             
   if(s.equals("two")){              
    list2.remove(s);             
   }         
  }         
  System.out.println(list2);

执行结果

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.learn.jdk16.util.ConcurrentModification.main(ConcurrentModification.java:40)


方法三、

         ArrayList<String> list3 = new ArrayList<String>();         
  list3.add("one");         
  list3.add("two");         
  list3.add("two");         
  list3.add("two");         
  list3.add("two");         
  Iterator<String> iter = list3.iterator();         
  while(iter.hasNext()){             
  String s = iter.next();            
   if(s.equals("two")){                 
    iter.remove();             
   }         
  }         
  System.out.println(list3);

执行结果

[one]

删除还是用迭代器的比较好,其它的都会有问题.
----------------------------------------------------------

 对ArrayList的操作我们可以通过索引象来访问,也可以通过Iterator来访问,只要不对ArrayList结构上进行修改都不会造成ConcurrentModificationException,单独用索引对ArrayList进行修改也不会造成该问题,造成该问题主要是在索引和Iterator混用。可以通过JDK的源码来说明该问题。

   首先看下AbstractList的Iterator内的代码:

 

  1. /** 
  2. *在Iterator的内部有个expectedModCount 变量, 
  3. *该变量每次初始化*Iterator的时候等于ArrayList的modCount,modCount记录了对ArrayList的结构修改次数, 
  4. *在通过Iterator对ArrayList进行结构的修改的时候都会将expectedModCount 与modCount同步, 
  5. *但是如果在通过Iterator访问的时候同时又通过索引的方式去修改ArrayList的结构的话, 
  6. *由于通过索引的方式只会修改modCount不会同步修改expectedModCount 就会导致 
  7. *modCount和expectedModCount 不相等就会抛ConcurrentModificationException, 
  8. *这也就是Iterator的fail-fast,快速失效的。所以只要采取一种方式操作ArrayList就不会出问题, 
  9. *当然ArrayList不是线程安全的,此处不讨论对线程问题。 
  10. * 
  11. */  
  12. int expectedModCount = modCount;  
  13. public E next() {  
  14.             checkForComodification();//判断modeCount与expectedModCount 是否相等,如果不相等就抛异常  
  15.         try {  
  16.         E next = get(cursor);  
  17.         lastRet = cursor++;  
  18.         return next;  
  19.         } catch (IndexOutOfBoundsException e) {  
  20.         checkForComodification();  
  21.         throw new NoSuchElementException();  
  22.         }  
  23. }  
  24.   
  25. public void remove() {  
  26.      if (lastRet == -1)  
  27.         throw new IllegalStateException();  
  28.           checkForComodification();//同样去判断modeCount与expectedModCount 是否相等  
  29.   
  30.       try {  
  31.         AbstractList.this.remove(lastRet);  
  32.         if (lastRet < cursor)  
  33.             cursor--;  
  34.         lastRet = -1;  
  35.         expectedModCount = modCount;//此处修改ArrayList的结构,所以要将expectedModCount 于modCount同步,主要是AbstractList.this.remove(lastRet);的remove方法中将modCount++了,导致了modCount与expectedModCount 不相等了。  
  36.        } catch (IndexOutOfBoundsException e) {  
  37.         throw new ConcurrentModificationException();  
  38.        }  
  39. }  
  40.   
  41. //判断modCount 与expectedModCount是否相等,如果不相等就抛ConcurrentModificationException异常  
  42. final void checkForComodification() {  
  43.      if (modCount != expectedModCount)  
  44.           throw new ConcurrentModificationException();  
  45. }  
 

故结论是:对ArrayList的操作采用一种遍历方式,要么索引,要么Iterator别混用即可。

下面是网上看见别人的解释:写道

Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 公司报销发票纸质的丢了怎么办 在京东上买的小天才手表坏了怎么办 美亚买东西过几天降价了怎么办 天猫买东西退款后又不想退了怎么办 自己写错了地址快递被签收了怎么办 在天猫购买东西不发货怎么办 在天猫买了东西不给我发货怎么办 天猫退货卖家收到货不退款怎么办 唯品会的账号找不回来了怎么办 从网上买的沙发物流超级慢怎么办 三星c5手机玩王者荣耀卡怎么办 买手机送话费的卡不想用了怎么办 到银行存钱被骗买保险了怎么办 去银行存钱被骗买了保险怎么办 京东申请退款后卖家又发货了怎么办 苹果6s没有4g网怎么办 花呗分期付款买手机额度不够怎么办 手机天猫不支持购买淘宝商品怎么办 天猫国际购买商品狠盾怎么办 在微信上微拍堂买东西被骗了怎么办 京东自营买到返修手机怎么办? 7p弯了怎么办能修复吗 农商银行app登录密码忘了怎么办 网址上的重庆时时彩不能提现怎么办 天天中彩票自己账户登录不了怎么办 天猫上卖王者荣耀的兑换码是怎么办 身份证借别人开淘宝永久封店怎么办 天猫店铺被扣12分怎么办 天猫法人变更之前的天猫贷款怎么办 在日本旅游遇到精日导游怎么办 银行资金交易异常卡被冻结怎么办 如果淘宝被盗了店铺乱上东西怎么办 快递不送货直接代售点签收怎么办 淘宝快递没收到却显示已签收怎么办 支付宝余额未满16受限怎么办 未满16岁支付宝余额受限怎么办 手机天猫购物买的数量大怎么办 扣扣游戏领礼包出现账号异常怎么办 美容院转让给别人客人要退钱怎么办 卖家毁约中介费担保费怎么办 天猫买东西店家不开增值税票怎么办