java.util.ConcurrentModificationException

1、代码如下:

[java]   view plain copy print ?
  1. public class MovetoCmd implements ITopoCommand {  
  2.   
  3.     public ResOperationResult execute(IOperator<AbstractTopoView> operator,final ResOperationResult resOperationResult) {  
  4.         final InternalTopoView topoView=(InternalTopoView) operator.getInternalOperator();  
  5.         final List<Element> list=topoView.getTopoModel().getSelectionElements();  
  6.         topoView.showWaitingLayer(true);  
  7.         isRemoveRootNode(list);  
  8.         final Component parentComponent=ResToolUtil.getComponentParent(topoView);  
  9.             if(parentComponent instanceof Frame){  
  10.                    
  11.                 Thread moveToThread=new Thread(new Runnable() {  
  12.                       
  13.                     public void run() {  
  14.                         // TODO Auto-generated method stub  
  15.                         try {  
  16.                             Thread.sleep(100);  
  17.                         } catch (InterruptedException e) {  
  18.                             // TODO Auto-generated catch block  
  19.                             e.printStackTrace();  
  20.                         }  
  21.                         if (SecurityFilterCmdTool.cmdSecurityFilter("0410", list)) {  
  22.                             MoveToDialog moveToDialog = new MoveToDialog((Frame)parentComponent, list);  
  23.                             moveToDialog.setTopoView(topoView);  
  24.                             topoView.showWaitingLayer(false);  
  25.                             moveToDialog.setVisible(true);  
  26.                             ResOperationResult excResOperationResult = new ResOperationResult();  
  27.                             excResOperationResult.setResult(true);  
  28.                             for (int i = 0; i < list.size(); i++) {  
  29.                                  ResObject resObject=TopoTool.elementToSymbolResObject(list.get(i));  
  30.                                  String resID=resObject.getResID();  
  31.                                  String name=resObject.getProperty("SYMBOL_NAME1");  
  32.                                  TopoTool.logSystemOperation("0410",resObject, ResourceManager.getString("newtopo""log.desc.moveto")+name+"("+resID+")"true);  
  33.                             }  
  34.                         }  
  35.                         else {  
  36.                         Poster.info(topoView, ResourceManager.getString("newtopo""msg.nopermission"));  
  37.                         resOperationResult.setResult(false);  
  38.                         }  
  39.                       
  40.                     }  
  41.                 });  
  42.                 moveToThread.start();  
  43.             }  
  44.             else if(parentComponent instanceof Dialog){  
  45.                    
  46.                 Thread moveToThread=new Thread(new Runnable() {  
  47.                       
  48.                     public void run() {  
  49.                         // TODO Auto-generated method stub  
  50.                         try {  
  51.                             Thread.sleep(100);  
  52.                         } catch (InterruptedException e) {  
  53.                             // TODO Auto-generated catch block  
  54.                             e.printStackTrace();  
  55.                         }  
  56.                         if (SecurityFilterCmdTool.cmdSecurityFilter("0410", list)) {  
  57.                             isRemoveRootNode(list);  
  58.                             MoveToDialog moveToDialog = new MoveToDialog((Frame)parentComponent, list);  
  59.                             moveToDialog.setTopoView(topoView);  
  60.                             topoView.showWaitingLayer(false);  
  61.                             moveToDialog.setVisible(true);  
  62.                             ResOperationResult excResOperationResult = new ResOperationResult();  
  63.                             excResOperationResult.setResult(true);  
  64.                             for (int i = 0; i < list.size(); i++) {  
  65.                                  ResObject resObject=TopoTool.elementToSymbolResObject(list.get(i));  
  66.                                  String resID=resObject.getResID();  
  67.                                  String name=resObject.getProperty("SYMBOL_NAME1");  
  68.                                  TopoTool.logSystemOperation("0410",resObject, ResourceManager.getString("newtopo""log.desc.moveto")+name+"("+resID+")"true);  
  69.                             }  
  70.                         }  
  71.                         else {  
  72.                         Poster.info(topoView, ResourceManager.getString("newtopo""msg.nopermission"));  
  73.                         resOperationResult.setResult(false);  
  74.                         }  
  75.                     }  
  76.                 });  
  77.                 moveToThread.start();  
  78.             }  
  79.   
  80.         return resOperationResult;  
  81.     }  
  82.     /** 
  83.      * 是否包含根节点,如果有,则删除 
  84.      * @param elements 
  85.      */  
  86.     public  void isRemoveRootNode(final List<Element> elements){  
  87.       
  88.                 // TODO Auto-generated method stub  
  89.                 for (Iterator iterator = elements.iterator(); iterator.hasNext();) {  
  90.                     Element element = (Element) iterator.next();  
  91.                     if(element instanceof TopoSubNetwork)  
  92.                     {  
  93.                         String mapParentID=element.getUserProperty("MAP_PARENT_ID").toString();  
  94.                         String treeParentID=element.getUserProperty("TREE_PARENT_ID").toString();  
  95.                         if (mapParentID!=null&&treeParentID!=null&&mapParentID.equalsIgnoreCase("-1")&&treeParentID.equalsIgnoreCase("-1")) {  
  96. <span style="color:#ff0000;">//                         elements.remove(element);//删除后进行遍历操作导致并发修改异常  
  97. </span>                         iterator.remove<span style="color:#ff0000;">();//修改方案  
  98. </span>                           
  99.                         }  
  100.                           
  101.                     }  
  102.   
  103.                 }  
  104.     }  
  105.       
  106.   
  107. }  

2、解决方案

   遍历删除时,不利用ArrayList的remove(object)方法,利用Iterator的remove()方法

3、分析

   ---------------------------ArrayList源码分析之remove(object)方法-----------------------------


 

[java]   view plain copy print ?
  1.     /** 
  2.      * Removes the first occurrence of the specified element from this list, 
  3.      * if it is present.  If the list does not contain the element, it is 
  4.      * unchanged.  More formally, removes the element with the lowest index 
  5.      * <tt>i</tt> such that 
  6.      * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> 
  7.      * (if such an element exists).  Returns <tt>true</tt> if this list 
  8.      * contained the specified element (or equivalently, if this list 
  9.      * changed as a result of the call). 
  10.      * 
  11.      * @param o element to be removed from this list, if present 
  12.      * @return <tt>true</tt> if this list contained the specified element 
  13.      */  
  14.     public boolean remove(Object o) {  
  15.     if (o == null) {  
  16.             for (int index = 0; index < size; index++)  
  17.         if (elementData[index] == null) {  
  18.             <span style="color:#ff0000;">fastRemove</span>(index);  
  19.             return true;  
  20.         }  
  21.     } else {  
  22.         for (int index = 0; index < size; index++)  
  23.         if (o.equals(elementData[index])) {  
  24.             <span style="color:#ff0000;">fastRemove(index);  
  25. </span>         return true;  
  26.         }  
  27.         }  
  28.     return false;  
  29.     }  


[java]   view plain copy print ?
  1.     /* 
  2.      * Private remove method that skips bounds checking and does not 
  3.      * return the value removed. 
  4.      */  
  5.     private void fastRemove(int index) {  
  6.         <span style="color:#ff0000;">modCount++;//仅仅增加值,modeCount和<span style="color:#ff0000;">expectedModCount不相同,导致并发修改异常</span>  
  7. </span>        int numMoved = size - index - 1;  
  8.         if (numMoved > 0)  
  9.             System.arraycopy(elementData, index+1, elementData, index,  
  10.                              numMoved);  
  11.         <span style="color:#ff0000;">elementData[--size] = null// Let gc do its work  
  12. </span>    }  

-------------------AbstractList的next方法--------------------------------------

[java]   view plain copy print ?
  1.     public E next() {  
  2.             <span style="color:#ff0000;">checkForComodification();  
  3. </span>     try {  
  4.         E next = get(cursor);  
  5.         lastRet = cursor++;  
  6.         return next;  
  7.         } catch (IndexOutOfBoundsException e) {  
  8.         checkForComodification();  
  9.         throw new NoSuchElementException();  
  10.         }  
  11.     }  

其中红色部分为并发修改检查,代码如下:

[java]   view plain copy print ?
  1. final void checkForComodification() {  
  2.     if (<span style="color:#ff0000;">modCount != expectedModCount</span>)  
  3.     throw new ConcurrentModificationException();  
  4. }  

其中,modCount为list结构性修改此次,结构性修改是指改变list大小等操作,初始值为0,增加或者删除操作都会修改expectedModCount的值,但是

arraylist的remove(object)仅仅增加modecount值,而abstractList迭代器的remove方法是修改的:

[java]   view plain copy print ?
  1.     public void remove() {  
  2.         if (lastRet == -1)  
  3.         throw new IllegalStateException();  
  4.             checkForComodification();  
  5.   
  6.         try {  
  7.         AbstractList.this.remove(lastRet);  
  8.         if (lastRet < cursor)  
  9.             cursor--;  
  10.         lastRet = -1;  
  11.         <span style="color:#ff0000;">expectedModCount = modCount;  
  12. </span>     } catch (IndexOutOfBoundsException e) {  
  13.         throw new ConcurrentModificationException();  
  14.         }  
  15.     }  

所以,产生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.util.ConcurrentModificationException)