zoukankan      html  css  js  c++  java
  • Java 集合快速失败异常

    快速失败



    JDK中,查看集合有很多关于快速失败的描述:

    注意,此实现不是同步的。如果多个线程同时访问一个哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须 保持外部同步。(结构上的修改是指添加或删除一个或多个映射关系的任何操作;仅改变与实例已经包含的键关联的值不是结构上的修改。)这一般通过对自然封装该映射的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedMap 方法来“包装”该映射。最好在创建时完成这一操作,以防止对映射进行意外的非同步访问,如下所示:

       Map m = Collections.synchronizedMap(new HashMap(...));由所有此类的“collection 视图方法”所返回的迭代器都是快速失败 的:在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器本身的 remove 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒在将来不确定的时间发生任意不确定行为的风险。

    注意,迭代器的快速失败行为不能得到保证,一般来说,存在非同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的做法是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。


    快速失败:对于非并发集合来说,在其进行迭代时,例如iterator迭代时,iterator是另起一个线程,若有其他线程(如Collection)进行结构修改(修改了增减了集合中的内容),这个迭代会马上感知到,并且立即抛出 ConcurrentModificationException 异常,而不是迭代完成后才告诉你出错了,引起快速失败。若用iterator进行修改则不会出现这个问题,如iterator.move();也就是说涉及到了多个线程间的同步问题



    示例代码:

    [java] view plain copy

    1. package CoreJava;  
    2.   
    3. import java.util.HashMap;  
    4. import java.util.Hashtable;  
    5. import java.util.Iterator;  
    6. import java.util.Map;  
    7. import java.util.Map.Entry;  
    8. import java.util.concurrent.ConcurrentHashMap;  
    9.   

    10. public class ConcurrentHashMapTest {  

    1. 11.     public static void main(String[] args) {  
    2. 12.   
    3. 13.         Hashtable<String, String> table = new Hashtable<String, String>();  
    4. 14.         table.put("a", "vb");  
    5. 15.         table.put("s", "er");  
    6. 16.         table.put("d", "fg");  
    7. 17.         table.remove("d");  
    8. 18.         Iterator<Entry<String, String>> iterator = table.entrySet().iterator();  
    9. 19.   
    10. 20.         while (iterator.hasNext()) {  
    11. 21.             System.out.println(iterator.next().getValue());  
    12. 22.             iterator.remove();//采用iterator直接进行修改 程序正常  
    13. 23.             // table.put("c", "wc");直接从hashtable增删数据就会报错  
    14. 24.             // table.remove("d");直接从hashtable增删数据就会报错 hashtable,hashmap等非并发集合 如果在迭代过程中增减了数据,  
    15. 25.         }  
    16. 26.   
    17. 27.         System.out.println("-----------");  
    18. 28.   
    19. 29.         HashMap<String, String> hashmap = new HashMap<String, String>();  
    20. 30.         hashmap.put("a", "vb");  
    21. 31.         hashmap.put("s", "er");  
    22. 32.         hashmap.put("d", "fg");  
    23. 33.         Iterator<Entry<String, String>> iterators = hashmap.entrySet()  
    24. 34.                 .iterator();  
    25. 35.   
    26. 36.         while (iterators.hasNext()) {  
    27. 37.             System.out.println(iterators.next().getValue());  
    28. 38.             iterators.remove();// 正常  
    29. 39.             // hashmap.remove("d");//直接从hashtable增删数据就会报错 hashtable,hashmap等非并发集合,如果在迭代过程中增减了数据,会快速失败 (一检测到修改,马上抛异常)  
    30. 40.         }  
    31. 41.   
    32. 42.         System.out.println("-----------");  
    33. 43.           
    34. 44.         ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();  
    35. 45.         map.put("a", "vb");  
    36. 46.         map.put("s", "er");  
    37. 47.         map.put("d", "fg");  
    38. 48.         Iterator<Entry<String, String>> mapiterator = map.entrySet().iterator();  
    39. 49.   
    40. 50.         while (mapiterator.hasNext()) {  
    41. 51.             System.out.println(mapiterator.next().getValue());  
    42. 52.             map.remove("d");// 正常 并发集合不存在快速失败问题  
    43. 53.             map.put("c", "wc");// 正常 并发集合不存在快速失败问题  
    44. 54.         }  
    45. 55.         System.out.println("-----------");  
    46. 56.         for (Map.Entry<String, String> entry : map.entrySet()) {  
    47. 57.             System.out.println(entry.getValue() + ", " + entry.getKey());  
    48. 58.         }  
    49. 59.         System.out.println("-----------");  
    50. 60.         for (Map.Entry<String, String> entry : table.entrySet()) {  
    51. 61.             System.out.println(entry.getValue() + ", " + entry.getKey());  
    52. 62.         }  
    53. 63.     }  
    54. 64.   
    55. 65.     /* 
    56. 66.      * final Entry<K,V> nextEntry() { if (modCount != expectedModCount) throw 
    57. 67.      * new ConcurrentModificationException(); Entry<K,V> e = next; if (e == 
    58. 68.      * null) throw new NoSuchElementException(); 
    59. 69.      *  
    60. 70.      * if ((next = e.next) == null) { Entry[] t = table; while (index < t.length 
    61. 71.      * && (next = t[index++]) == null) ; } current = e; return e; } 
    62. 72.      */  
    63. 73.   

    74. }  

             快速失败异常:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常

             解决方法:

     

                       A:迭代器删除

     

     

                       B:锁抢回来。集合自已删除。(前提:线程同步的集合)

     

  • 相关阅读:
    LeetCode> 989. 数组形式的整数加法
    Java> Java核心卷读书笔记
    npx是干嘛的
    typescript教程
    http Get 发送body数据
    59. 螺旋矩阵 II
    使用静态代理模式实现公用的报表导出功能
    win10更新后 sqlserver客户端连接一段时间后报错 CryptUnprotectData: Win32 错误:-2146893813 (Microsoft.SqlServer.RegSvrEnum)或该项不适用于在指定状态下使用
    Docker Compose-Window
    Docker的容器使用与连接-Window
  • 原文地址:https://www.cnblogs.com/ziq711/p/5603947.html
Copyright © 2011-2022 走看看