zoukankan      html  css  js  c++  java
  • Hashtable 删除元素, 抛出异常 java.util.ConcurrentModificationException

    今天在对一个Hashtable对象进行 搜索 -> 删除 操作时遇到的一个问题,开始的使用我使用的是Hashtable的Iterator,然后直接执行:

    Hashtable.remove(key); 抛出异常  java.util.ConcurrentModificationException

    查了一下java api doc,相关介绍如下:

    由迭代器返回的 Iterator 和由所有 Hashtable 的“collection 视图方法”返回的 Collection 的 listIterator 方法都是快速失败的:在创建 Iterator 之后,如果从结构上对 Hashtable 进行修改,除非通过 Iterator 自身的移除或添加方法,否则在任何时间以任何方式对其进行修改,Iterator 都将抛出 ConcurrentModificationException。因此,面对并发的修改,Iterator 很快就会完全失败,而不冒在将来某个不确定的时间发生任意不确定行为的风险。由 Hashtable 的键和值方法返回的 Enumeration不是快速失败的。

    Hashtable<Integer,Integer> t = new Hashtable<Integer,Integer>();
         
         for(int i=0;i<10;i++)
         {
          t.put(i,i*10);
         }   
         
         System.out.println("t.size():" + t.size());
         System.out.println(t.get(6));
         
         System.out.println();       
             
            Iterator<Integer> i = t.keySet().iterator();
         
         while(i.hasNext())
         {
          int key = i.next();
          
          if(key == 3)      
          {
           //t.remove(key);  //这样删除,抛出异常 java.util.ConcurrentModificationException       
           i.remove(); //只有这样,才可以成功的删除一个元素
          }
         }
         
         System.out.println("t.size():" + t.size());     
         System.out.println(t.get(6));

    使用上面这种t.keySet().iterator();方式,如果在多线程情况下,也是会抛出 java.util.ConcurrentModificationException

    在多线程并发的情况下,在增加、修改、删除、遍历时全加上 synchronized :

    public synchronized void delKey(int key)
     {  
      Iterator<Integer> i = t.keySet().iterator();
      while(i.hasNext())
         {
          int abc = i.next();
          
          //t.remove(key); //抛出异常 java.util.ConcurrentModificationException
       
          if(abc == key)
           i.remove(); //只有这样,才可以成功的删除一个元素
         }     
     }

    当在多线路中调用 delKey()时,必须在定义delKey()方法前使用:synchronized,以保证多线程调用安全。

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------

    其实还有一种更早的(更原始的)的安全方法,使用Enumeration,这种方式不管是在单线程还是在多线程中执行都是安全的(注意下面的特别说明):

    Hashtable<Integer,Integer> t = new Hashtable<Integer,Integer>();
         
         for(int i=0;i<10;i++)
         {
          t.put(i,i*10);
         }    
         
         System.out.println("t.size():" + t.size());
         System.out.println(t.get(6));
         
         System.out.println();    
         
         Enumeration<Integer> e = t.keys();
         while(e.hasMoreElements())
         {
          int key = e.nextElement();
          
          if(key == 3)
          t.remove(key);
         } 
         
         System.out.println("t.size():" + t.size());     
         System.out.println(t.get(6));

    特别注意:

    虽然使用Enumeration来遍历元素是线程安全的,高并发的情况下进行增加、修改、遍历,也不会抛什么异常,但如果在遍历Enumeration的同时删除里面的一个元素虽不会抛出什么异常,但结果可能不是你想像的:list = new Vector<String>();
      
      list.add("1");
      list.add("2");
      list.add("3");
      list.add("4");
      list.add("5");
      list.add("6");
      
      Enumeration<String> i = list.elements();
      while(i.hasMoreElements())
      {
       String str = i.nextElement();
       
       System.out.println(str);
       
       list.removeElement(str); //在这里删除
      }

    //输出结果:

    1

    3

    5

    我看到这个结果,我是真的很意外。

    2011-04-18

  • 相关阅读:
    《快速开发》通过Maven创建WebService项目Hello World!
    《常见问题集》Eclipse
    《常见问题集》Maven
    Eclipse + Jersey 发布RESTful WebService(一)了解Maven和Jersey,创建一个WS项目(成功!)
    Java2WSDL 和 WSDL2Java(Axis)
    Eclipse + Apache Axis2 发布RESTful WebService(一)基础知识
    Eclipse + Apache Axis2 发布SOAP WebService(三)第一个程序Hello Axis2 SOAP!
    Eclipse + Apache Axis2 发布RESTful WebService(三)第一个程序Hello Axis2 !(未成功)
    Eclipse + Apache Axis2 发布RESTful WebService(二)配置开发环境
    学习 JSP:第三步 JSP基础(未完)
  • 原文地址:https://www.cnblogs.com/personnel/p/4583045.html
Copyright © 2011-2022 走看看