What do you know about fail safe and fail fast

What do you know about fail safe and fail fast

brief introduction

When we use collection classes, we usually need to traverse the elements in the collection and process the elements in the traversal. At this time, we need to use the iterator. Friends who often write programs should know that the collection data cannot be modified during the traversal of the iterator, otherwise a concurrentmodificationexception will be thrown.

Because of the existence of concurrentmodificationexception, iterators are divided into two categories: fail fast and fail safe.

fail-fast Iterator

Fail fast can be seen by its name. It means to fail very fast. That is, if the structure of the set is modified during traversal, an error will be reported immediately.

Fail fast usually throws a concurrentmodificationexception in the following two cases:

In a single threaded environment, if the structure of the collection is modified by calling other methods instead of the remove method of the iterator itself after the iterator is created, an error will be reported.

If an iterator is created in one thread and the structure of the collection is modified in another thread, an error will be reported.

Let's take a look at an example of fail fast:

        Map<Integer,String> users = new HashMap<>();

        users.put(1,"jack");
        users.put(2,"alice");
        users.put(3,"jone");

        Iterator iterator1 = users.keySet().iterator();

        //not modify key,so no exception
        while (iterator1.hasNext())
        {
            log.info("{}",users.get(iterator1.next()));
            users.put(2,"mark");
        }

In the above example, we build a map, and then traverse the key of the map. In the process of traversal, we modify the value of the map.

It is found that the program executes perfectly without reporting any exceptions.

This is because we traverse the key of the map. As long as the key of the map is not manually modified, there is no problem.

Take another example:

Map<Integer,"jone");

        Iterator iterator1 = users.keySet().iterator();

        Iterator iterator2 = users.keySet().iterator();
        //modify key,get exception
        while (iterator2.hasNext())
        {
            log.info("{}",users.get(iterator2.next()));
            users.put(4,"mark");
        }

In the above example, we modified the key while traversing the key of the map. In this case, an error will be reported.

Principle of fail fast

Why is an exception reported when the structure of the set is modified?

Let's take ArrayList as an example to explain the principle of fail fast.

In abstractlist, a modcount variable is defined:

protected transient int modCount = 0;

In the process of traversal, the checkforcomodification() method will be called to detect modcount:

      public E next() {
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (indexoutofboundsexception e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

If the test result is not as expected, an error will be reported:

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

When creating the iterator, the current modcount will be copied for comparison, and this modcount will change every time the collection is modified, resulting in the inconsistency between the modcount in the iterator and the existing modcount.

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.set(lastRet,e);
                expectedModCount = modCount;
            } catch (indexoutofboundsexception ex) {
                throw new ConcurrentModificationException();
            }
        }

Note that fail fast does not guarantee that all modifications will report errors. We cannot rely on concurrentmodificationexception to judge whether the collection is modified during traversal.

Fail-safe Iterator

Let's talk about fail safe again. Fail safe means that no error will be reported if the collection is modified during traversal.

The following types of concurrent package are fail safe. Take a concurrent HashMap example:

Map<Integer,String> users = new ConcurrentHashMap<>();

        users.put(1,"mark");
        }

        Iterator iterator2 = users.keySet().iterator();
        //modify key,"mark");
        }

The above example performs perfectly and will not report an error.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>