Thread Safety issues with Vector and Hashtable.

Overview

Even though these classes are legacy replaces which were replaced in Java 1.2 (1998) they remain widely using. One misconception is that they are synchronized and there for thread safe.

Is Iterator thread safe?

For many collections the Iterator is not thread safe. They fail fast by throwing a ConcurrentModiciationException. However throwing this exception is not guaranteed and the counter used to detect this situation is not volatile.

CollectionIterator behavior
ArrayList, LinkedList, TreeSetUsually throws a ConcurrentModicationException
CopyOnWriteArraySet, CopyOnWriteArrayListConsistent for the state of the collection at a given point in time
ArrayBlockingQueue, LinkedBlockingQueueWeakly consistent, won't throw an error
ArrayBlockingQueue, LinkedBlockingQueueAlso weakly consistent, won't throw an error, the Iterator is sorted
PriorityQueueAlso weakly consistent, even though the collection is sorted , the Iterator is not sorted.

Enumeration is thread safe?

Every method is synchronized so the collection should be thread safe, unfortunately Enumeration has to be used in two parts, hasMoreElements() and nextElement(), each method is thread safe, but another thread can make changes in between these two calls which can cause the Enumeration to fail.

Vector ints = new Vector();
ints.add(1);
ints.add(2);
Enumeration en = ints.elements();
int count = 0;
while(en.hasMoreElements()) {
    OnThreadB: if(count++ == 1) ints.remove(0);
    System.out.println(en.nextElement());
}
The line between hasMoreElements() and nextElement() show what another thread can randomly do. This causes the nextElement() to throw a NoSuchElementException.

How to make Enumeration thread safe?

You need to lock the collection for the life of the Enumeration, This can be used for Iterators as well (though for different reasons)

Vector ints = new Vector();
ints.add(1);
ints.add(2);
synchronized (ints) {
    Enumeration en = ints.elements();
    while(en.hasMoreElements()) {
         // another there cannot do some thing here.
        System.out.println(en.nextElement());
    }
}

Conclusion

Don't assume that making every method synchronized will make a collection thread safe, you also have to consider whether methods will be used in combination and whether one depends on another.

Ideally you should make every method independent to avoid this issue.

Comments

Popular posts from this blog

Low Latency Microservices, A Retrospective

Unusual Java: StackTrace Extends Throwable

System wide unique nanosecond timestamps