• fail-fast vs fail-safe iterator in Java


    Reference

    [1] http://netjs.blogspot.co.uk/2015/05/fail-fast-vs-fail-safe-iterator-in-java.html

    The collections which are there from Java 1.2 (or even legacy) like ArrayList, Vector, HashSet, LinkedHashSet, TreeSet, HashMap all have fail-fast iterator whereas Concurrent collections added in Java 1.5 like ConcurrrentHashMap, CopyOnWriteArrayList, CopyOnWriteArraySet have fail-safe iterator. The iterator of EnumSet is weakly consistent: it will never throw ConcurrentModificationException and it may or may not show the effects of any modifications to the set that occur while the iteration is in progress. 

    The key differences between the fail-fast and fail-safe iterator

      1. fail-fast iterator throws ConcurrentModificationException if the underlying collection is structurally modified in any way except through the iterator's own remove or add methods.
        fail-safe iterator doesn't throw ConcurrentModificationException.
      2. fail-fast iterator work on the original collection.
        fail-safe iterator makes a copy of the underlying structure and iteration is done over that snapshot. Drawback of using a copy of the collection rather than original collection is that the iterator will not reflect additions, removals, or changes to the collection since the iterator was created.
      3. fail-fast iterator provides remove, set, and add operations. Note that not all the iterators support all these methods. As exp.ListIterator supports add() method but the general iterator doesn't.
        With fail-safe iterator element-changing operations on iterators themselves (remove, set, and add) are not supported. These methods throw UnsupportedOperationException.

    fail-fast iterator in Java

    An iterator is considered fail-fast if it throws a ConcurrentModificationException under either of the following two conditions:

    • In multi-threaded environment, if one thread is trying to modify a Collection while another thread is iterating over it.
    • Even with single thread, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

    fail-fast iterator fails if the underlying collection is structurally modified at any time after the iterator is created, thus the iterator will throw a ConcurrentModificationException if the underlying collection is structurally modified in any way except through the iterator's own remove or add (if applicable as in list-iterator) methods.

    Note that structural modification is any operation that adds or deletes one or more elements; merely setting the value of an element (in case of list) or changing the value associated with an existing key (in case of map) is not a structural modification.

    Mostly Iterators from java.util package throw ConcurrentModificationException if collection was modified by collection's methods (add / remove) while iterating

    Also note that according to Oracle Docs fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

    1) The following codes will throw ConcurrentModificationException

    public class FailFastModification {
        public static void main(String[] args) {
            // creating map
            Map <String,String> cityMap = new HashMap<String,String>();
            cityMap.put("1","New York City" );
            cityMap.put("2", "New Delhi");
            cityMap.put("3", "Newark");
            cityMap.put("4", "Newport");
            // getting iterator
            Iterator <String> itr = cityMap.keySet().iterator();
            while (itr.hasNext()){
                System.out.println(cityMap.get(itr.next()));
                // trying to add new value to a map while iterating it, will throw ConcurrentModificationException
                cityMap.put("5", "New City");
            }        
        }
    
    }

    2) The following method to just update values is allowed and will not throw ConcurrentModificationException

    public class FailFastModification {
        public static void main(String[] args) {
            // creating map
            Map <String,String> cityMap = new HashMap<String,String>();
            cityMap.put("1","New York City" );
            cityMap.put("2", "New Delhi");
            cityMap.put("3", "Newark");
            cityMap.put("4", "Newport");
            // getting iterator
            Iterator <String> itr = cityMap.keySet().iterator();
            while (itr.hasNext()){
                System.out.println(cityMap.get(itr.next()));
                // updating existing value while iterating
                cityMap.put("3", "New City");
            }        
        }
    }

    2) The following method to remove values using iterator itself is allowed and will not throw ConcurrentModificationException

    public class FailFastModification {
        public static void main(String[] args) {
            Map <String,String> cityMap = new HashMap<String,String>();
            cityMap.put("1","New York City" );
            cityMap.put("2", "New Delhi");
            cityMap.put("3", "Newark");
            cityMap.put("4", "Newport");
            System.out.println("size before iteration " + cityMap.size());
            Iterator <String> itr = cityMap.keySet().iterator();
            while (itr.hasNext()){
                System.out.println(cityMap.get(itr.next()));
                // removing value using iterator remove method
                itr.remove();
            }
            System.out.println("size after iteration " + cityMap.size());        
        }
    }

    Fail Safe iterator

    In case of fail-safe iterator, ConcurrentModificationException is not thrown as the fail-safe iterator makes a copy of the underlying structure and iteration is done over that snapshot. 
    Since iteration is done over a copy of the collection so interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException.

    Drawback of using a copy of the collection rather than original collection is that the iterator will not reflect additions, removals, or changes to the collection since the iterator was created. Element-changing operations on iterators themselves (remove, set, and add) are not supported. These methods throw UnsupportedOperationException.

    Iterator of CopyOnWriteArrayList is an example of fail-safe Iterator also iterator provided by ConcurrentHashMap keySet is fail-safe and never throws ConcurrentModificationException.

    Look at the following example of a fail-safe iterator

    public class FailSafeTest {
     public static void main(String[] args) {
    
      List <String> cityList = new CopyOnWriteArrayList<String>();
      cityList.add("New York City");
      cityList.add("New Delhi");
      cityList.add("Newark");
      cityList.add("Newport");  
      Iterator<String> itr = cityList.iterator();
      while (itr.hasNext())
             {         
              System.out.println(itr.next());
              cityList.add("NewCity");
              //itr.remove();
             }
     }
    }

    This program won't throw ConcurrentModificationException as iterator used with CopyOnWriteArrayList is fail-safe iterator.

    If we uncomment the line //itr.remove(); this program will throw UnsupportedOperationException as fail-safe iterator does not support remove, set, and add operations.

    Summary

    • An iterator is considered fail-fast if it throws a ConcurrentModificationException in case the underlying collection's structure is modified.
    • While iterating a list or a map values can be updated, only if an attempt is made to add or remove from the collection ConcurrentModificationException will be thrown by fail-fast iterator.
    • Fail-fast iterators throw ConcurrentModificationException on a best-effort basis and fail-fast behavior of an iterator cannot be guaranteed.
    • fail-safe iterator works with a copy of the collection rather than the original collection thus interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException.
    • remove, set, and add operations are not supported with fail-safe iterator.
  • 相关阅读:
    【MongoDB】windows下搭建Mongo主(Master)/从(slave)数据库同步
    视图与暂时表
    Highcharts构建分组分类坐标轴
    iOS可持续化集成: Jenkins + bundler + cocoapods + shenzhen + fastlane + pgyer
    Internationalization composition diagram
    ASCII表 基本记忆 -- C
    Java内部类
    Idea过期继续激活~
    Spark SQL 用户自定义函数UDF、用户自定义聚合函数UDAF 教程(Java踩坑教学版)
    Spark源码分析之Spark-submit和Spark-class
  • 原文地址:https://www.cnblogs.com/codingforum/p/6947532.html
Copyright © 2020-2023  润新知