0

When I ran the following code

Caught expected ConcurrentModificationException

is printed which is expected but strange thing is on second iteration no exception is being caught and

Failed to catch expected ConcurrentModificationException

is printed. I am really not sure why for second time it is not caught.

public class TestLHS {

    public static void main(String[] args) {
        LinkedHashSet<Integer> lhSet = new LinkedHashSet<Integer>();
        Integer one = new Integer(1);
        Integer two = new Integer(2);
        Integer three = new Integer(3);
        Integer four = new Integer(4);
        Integer cinco = new Integer(5);

        // Add the three objects to the LinkedHashSet.
        // By its nature, the LinkedHashSet will iterate in
        // order of insertion.
        lhSet.add(one);
        lhSet.add(two);
        lhSet.add(three);

        // 1. Iterate over set. try to insert while processing the
        // second item. This should throw a ConcurrentModificationEx
        try {
            for (Iterator<Integer> it = lhSet.iterator(); it.hasNext();) {
                Integer num = (Integer) it.next();
                if (num == two) {
                    lhSet.add(four);
                }
                System.out.println(num);
            }
        } catch (ConcurrentModificationException ex) {
            System.out.println("Caught expected ConcurrentModificationException");
        }

        // 2. Iterate again, this time inserting on the (old) 'last'
        // element. This too should throw a ConcurrentModificationEx.
        // But it doesn't.
        try {
            for (Iterator<Integer> it = lhSet.iterator(); it.hasNext();) {
                Integer num = (Integer) it.next();
                if (num == four) {
                    lhSet.add(cinco);
                }
                System.out.println(num);
            }

            System.out.println("Failed to catch expected ConcurrentModificationException");
        } catch (ConcurrentModificationException ex) {
            System.out.println("Caught expected ConcurrentModificationException");
        }

    }
}

Can someone explain this behavior?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
T-Bag
  • 10,916
  • 3
  • 54
  • 118

4 Answers4

1

If you look at the code for LinkedHashMap (or any class that implements Iterator) you will see that ConcurrentModificationException is checked in the next() method.

You get ConcurrentModificationException on the first for loop because you add when 'num' == 'two'; the iterator still has 'three' left so the loop continues. The subsequent call to next() is where the exception is thrown.

On the second loop, you add when the last current element has been iterated, therefore you don't call next() and no ConcurrentModificationException is thrown.

ayahuasca
  • 556
  • 10
  • 9
1

Let's look at the documentation:

if the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.

Notice that it's not clear exactly which iterator method will throw the exception. Let's check the source:

public final boolean hasNext() {
    return next != null;
}

// called by LinkedKeyIterator.next()
final LinkedHashMap.Entry<K,V> nextNode() {
    LinkedHashMap.Entry<K,V> e = next;
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    if (e == null)
        throw new NoSuchElementException();
    current = e;
    next = e.after;
    return e;
}

As you can see, the exception is thrown by the next() method, not by hasNext(). Since four is the last element in the set, next is already null, so the next call to hasNext() returns false and next() isn't called again. Therefore, the concurrent modification is not observed and no exception is thrown.

See also Why isn't this code causing a ConcurrentModificationException?

shmosel
  • 49,289
  • 6
  • 73
  • 138
1

This is a known issue with number 6258302, posted at JDK bugList. The same can be found here

T-Bag
  • 10,916
  • 3
  • 54
  • 118
gaurs
  • 575
  • 1
  • 5
  • 19
0

This is clearly mentioned in Java Docs:-

That- this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, 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

Note:- that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore,

:- it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

more details refer- https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

gajju_15
  • 527
  • 4
  • 17