12

Enumeration doesn't throw ConcurrentModificationException , why?

See below code .

public static void main(String[] args) {

    Vector<String> v=new Vector<String>();
    v.add("Amit");
    v.add("Raj");
    v.add("Pathak");
    v.add("Sumit");
    v.add("Aron");
    v.add("Trek");

    Enumeration<String> en=v.elements();

    while(en.hasMoreElements())
    {
        String value=(String) en.nextElement();
        System.out.println(value);
        v.remove(value);

    }

}

It only prints :

Amit
Pathak
Aron

Why is this such behavior . Can we say that Enumerator is thread safe.

Edit: When working with Iterator it throws ConcurrentModificationException in single thread application.

public static void main(String[] args) {

    Vector<String> v=new Vector<String>();
    v.add("Amit");
    v.add("Raj");
    v.add("Pathak");
    v.add("Sumit");
    v.add("Aron");
    v.add("Trek");

    Iterator<String> it=v.iterator();
    while(it.hasNext())
    {
        String value=(String) it.next();
        System.out.println(value);
        v.remove(value);
    }
}

Please check.

amicngh
  • 7,831
  • 3
  • 35
  • 54
  • 1
    Please read http://stackoverflow.com/questions/948194/different-using-java-util-enumeration-and-iterator – Garbage Jun 04 '12 at 11:09
  • What is the background of this question? Are you considering using enumerations instead of iterators in a multi threaded enviroment? – Ludwig Magnusson Jun 04 '12 at 11:09
  • Is there more code somewhere that we should know about? There is no multithreading in the sample code above, so unless you have a specific reason to blame thread-safety I think you are a bit off-track here – posdef Jun 04 '12 at 11:09
  • Note that ConcurrentModificationException has nothing to do with concurrency in the sense of multithreading or thread safety. – sfussenegger Jun 04 '12 at 11:11
  • Enumeration is not GUARANTEED to throw ConcurrentModificationException, it only does so when it notices an inconsistent state in the enumerated object. Also:[The functionality of this interface (Enumeration) is duplicated by the Iterator interface. In addition, Iterator adds an optional remove operation, and has shorter method names. New implementations should consider using Iterator in preference to Enumeration.](http://docs.oracle.com/javase/1.5.0/docs/api/) – Hot Licks Jun 04 '12 at 11:12
  • @HotLicks Are you saying , Enumeration may throw ConcurrentModificationException ? – amicngh Jun 04 '12 at 11:15
  • @sfussenegger If such a case , why we go for ConcurrentHashMap rather than using HashMap ? – amicngh Jun 04 '12 at 11:17
  • @Garbage : this is not the duplicate , My context is different. – amicngh Jun 04 '12 at 11:23
  • @amicngh see my extended answer below – sfussenegger Jun 04 '12 at 11:29
  • @sfussenegger : Can you give some sample where Enumeration throw ConcurrentModificationException for my better understanding. – amicngh Jun 04 '12 at 11:48
  • @amicngh see explanation after "EDIT:" in my answer below – sfussenegger Jun 04 '12 at 12:16
  • @amicngh: see the example in my answer for the case where Enumeration throws ConcurrentModificationException. – dragon66 Jun 04 '12 at 15:11
  • @amicngh -- On checking I see that ConcurrentModificationException isn't listed for the Enumeration interface in 1.5. Don't know if there are any oddball ways it might occur. – Hot Licks Jun 04 '12 at 16:56

7 Answers7

12

Note that ConcurrentModificationException has nothing to do with concurrency in the sense of multithreading or thread safety. Some collections allow concurrent modifications, some don't. Normally you can find the answer in the docs. But concurrent doesn't mean concurrently by different threads. It means you can modify the collection while you iterate.

ConcurrentHashMap is a special case, as it is explicitly defined to be thread-safe AND editable while iterated (which I think is true for all thread-safe collections).

Anyway, as long as you're using a single thread to iterate and modify the collection, ConcurrentHashMap is the wrong solution to your problem. You are using the API wrongly. You should use Iterator.remove() to remove items. Alternatively, you can make a copy of the collection before you iterate and modify the original.

EDIT:

I don't know of any Enumeration that throws a ConcurrentModificationException. However, the behavior in case of a concurrent modification might not be what you expect it to be. As you see in you example, the enumeration skips every second element in the list. This is due to it's internal index being incremented regardless of removes. So this is what happens:

  • en.nextElement() - returns first element from Vector, increments index to 1
  • v.remove(value) - removes first element from Vector, shifts all elements left
  • en.nextElement() - returns second element from Vector, which now is "Pathak"

The fail-fast behavior of Iterator protects you from this kind of things, which is why it is generally preferable to Enumberation. Instead, you should do the following:

Iterator<String> it=v.iterator();
while(it.hasNext())
{
    String value=(String) it.next();
    System.out.println(value);
    it.remove(); // not v.remove(value); !!
}

Alternatively:

for(String value : new Vector<String>(v)) // make a copy
{
    String value=(String) it.next();
    System.out.println(value);
    v.remove(value);
}

The first one is certainly preferable, as you don't really need the copy as long as you use the API as it is intended.

sfussenegger
  • 35,575
  • 15
  • 95
  • 119
4

Enumeration doesn't throw ConcurrentModificationException , why?

Because there is no path in the code being invoked which throws this exception. Edit: I am referring to the implementation provided by the Vector class, not about the Enumeration interface in general.

Why is this such behavior . Can we say that Enumerator is thread safe.

It is thread-safe in a sense that the code executed is properly synchronized. However, I don't think the result your loop yields is what you would except.

The reason for your output is that the Enumeration object maintains a counter, which is incremented after every invokation of nextElement(). This counter is not aware of your invokation of remove().

MartinK
  • 1,938
  • 19
  • 18
  • My understanding is Enumeration has reference to collection as Iterator has. As soon we remove element from vector it is noticed in Enumeration .then why it is printing 3 not all 5 if we are printing first and then removing. – amicngh Jun 04 '12 at 11:21
  • That's the point. The Enumeration does not notice your invokation of remove (which would make it necesarry to decrement it's index variable). – MartinK Jun 04 '12 at 11:29
3

the fail-fast behaviour which throws the ConcurrentModificationException is only implemented for the Iterator as you can read in http://docs.oracle.com/javase/6/docs/api/java/util/Vector.html

Hachi
  • 3,237
  • 1
  • 21
  • 29
3

Concurrent modification here has nothing to do with threads.

Concurrency here simply means that you are modifying the collection while you are iterating over it. (In your example this happens in the same thread.)

Iterators and enumerations of collections can throw ConcurrentModificationException in this case, but don't have to. The ones that do exhibit fail-fast behaviour. Apparently, the enumeration of Vector isn't fail-fast.

Thread-safety obviously involves multiple threads somehow. Vector is thread-safe only in the sense that its operations (like add, get, etc.) are synchronized. This is to avoid non-deterministic behaviour when one thread is adding an element while at the same time another thread is trying to remove one for example.

Now, when one thread is structurally modifying your collection while another thread is iterating over it, you have to deal with both thread-safety and concurrent modification issues. In this case, and probably in general, it is safest not to rely on ConcurrentModificationException being thrown. It is best to choose the appropriate collection implementation (a thread-safe one for example) and avoid/disallow concurrent modification yourself.

Some iterators allow adding/setting/removing elements through the iterator itself. This can be a good alternative if you really need concurrent modification.

eljenso
  • 16,789
  • 6
  • 57
  • 63
1

Short answer: It's a bonus feature that was invented after enumeration was already there, so the fact that the enumerator does not throw it does not suggest anything particular.

Long answer:
From wikipedia:

Collection implementations in pre-JDK 1.2 [...] did not contain a collections framework. The standard methods for grouping Java objects were via the array, the Vector, and the Hashtable classes, which unfortunately were not easy to extend, and did not implement a standard member interface. To address the need for reusable collection data structures [...] The collections framework was designed and developed primarily by Joshua Bloch, and was introduced in JDK 1.2.

When the Bloch team did that, they thought it was a good idea to put in a new mechanism that sends out an alarm (ConcurrentModificationException) when their collections were not synchronized properly in a multi-threaded program. There are two important things to note about this mechanism: 1) it's not guaranteed to catch concurrency bugs -- the exception is only thrown if you are lucky. 2) The exception is also thrown if you misuse the collection using a single thread (as in your example).

So, a collection not throwing an ConcurrentModificationException when accessed by multiple threads does not imply it's thread-safe either.

Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
0

It depends on how you get the Enumeration. See the following example, it does throw ConcurrentModificationException:

import java.util.*;

public class ConcurrencyTest {  
    public static void main(String[] args) {  

        Vector<String> v=new Vector<String>();
        v.add("Amit");
        v.add("Raj");
        v.add("Pathak");
        v.add("Sumit");
        v.add("Aron");
        v.add("Trek");

        Enumeration<String> en=Collections.enumeration(v);//v.elements(); 

        while(en.hasMoreElements())
        {
            String value=(String) en.nextElement();
            System.out.println(value);
            v.remove(value);
        }              

        System.out.println("************************************");

        Iterator<String> iter = v.iterator();  
           while(iter.hasNext()){  
              System.out.println(iter.next());  
              iter.remove();  
              System.out.println(v.size());  
        }  
    }  
}  

Enumeration is just an interface, it's actual behavior is implementation-dependent. The Enumeration from the Collections.enumeration() call wraps the iterator in someway, so it's indeed fail-fast, but the Enumeration obtained from calling the Vector.elements() is not.

The not-fail-fast Enumeration could introduce arbitrary, non-deterministic behavior at an undetermined time in the future. For example: if you write the main method as this, it will throw java.util.NoSuchElementException after the first iteration.

public static void main(String[] args) {  

        Vector<String> v=new Vector<String>();
        v.add("Amit");
        v.add("Raj");
        v.add("Pathak");

        Enumeration<String> en = v.elements(); //Collections.enumeration(v);

        while(en.hasMoreElements())
        {   
            v.remove(0);
            String value=(String) en.nextElement();
            System.out.println(value);
        }       
    }  
dragon66
  • 2,645
  • 2
  • 21
  • 43
-1

remove the v.remove(value) and everything will work as expected

Edit: sorry, misread the question there

This has nothing to do with threadsafety though. You're not even multithreading so there is no reason Java would throw an exception for this.

If you want exceptions when you are changing the vector make it Unmodifiable

vanleeuwenbram
  • 1,289
  • 11
  • 19