Wednesday, March 28, 2007

CME

Yesterday in our project we were getting ConcurrentModificationException.
It occurs when you modify the underlying collection on which the iterator is iterating.

Ideally we should use the same iterator to modify the collection.

This could occur when there is only one thread.

When there are more than one threads one thread might modify the underlying collection when other thread is iterating using the iterator on that collection.

When we synchronized the access methods to that hashmap which was throwing the exception then the exception did not occur. But when we increased the no. of concurrent threads then the exception reoccured.

I feel that the pattern that is used in our project is incorrect.

We are using singleton object which contains a hashmap.
We updated and read the hashmap very frequently.

The resolution of the problem is using 1. in memory database 2. using the table in the database and maintaining the cache of this table in memory

Lets see whether any on my solutions are proved true.


1.1 The Concurrent Modification Problem
The Concurrent Modification Problem (CMP), which arises in
the context of the Java Collections Framework (JCF) [5], is a typical
conformance constraint problem that we will use as a running
example in the sequel. JCF Iterators are used to iterate over
the contents of an underlying collection (e.g., a HashSet, which
implements the Set interface). A fundamental constraint on the
use of iterators is that once an iterator object oi is created for a
collection oc, it may be used only as long as the collection oc is
not modified, not counting modifications made via oi. This restriction
ensures that the internal state invariants of oi are not corrupted
by another iterator, or by direct update to the collection. JCF collections
detect violations of this constraint dynamically, and throw
class Make {
private Worklist worklist;
public static void main (String[] args) {
Make m = new Make();
m.initializeWorklist(args);
m.processWorklist(); }
void initializeWorklist(String[] args) {
...; worklist = new Worklist(); ... }
void processWorklist() {
HashSet s = worklist.unprocessedItems();
for (Iterator i = s.iterator(); i.hasNext()){
Object item = i.next(); // CME may occur here
if (...) processItem(item);
} }
void processItem(Object i) { ...; doSubproblem(...); }
void doSubproblem(...) {
... worklist.addItem(newitem); ... }
}
public class Worklist {
HashSet s;
public Worklist() { s = new HashSet(); ... }
public void addItem(Object item) { s.add(item); }
public HashSet unprocessedItems() { return s; }
}
Figure 1: An erroneous Java program fragment throwing CME.
ConcurrentModificationException(or CME) when it occurs
(note that the name of the exception is misleading, since it often
occurs in single-threaded programs). We will use “CMP” to refer
to the problem of statically determining whether a JCF client may
cause CME to be thrown.
Consider the Java code fragment in Fig. 1. Here, an iterator is created
on a worklist, which is implemented using a HashSet, a
JCF collection class. The iterator is then used to process each item on
the worklist in succession. We observe that CME can be thrown during
item processing, since the nested call to doSubproblem(. . . )
causes worklist.addItem(newitem) to be called, which
will in turn update the underlying HashSet while the iterator is
still active. On the next iteration, the call to i.next() would
cause CME to be thrown.



/* 0 */ Set v = new Set();
/* 1 */ Iterator i1 = v.iterator();
/* 2 */ Iterator i2 = v.iterator();
/* 3 */ Iterator i3 = i1;
/* 4 */ i1.next();
// The following update via i1 invalidates the
// iterator referred to by i2.
/* 5 */ i1.remove();
/* 6 */ if (...) { i2.next(); /* CME thrown */ }
// i3 refers to the same, valid, iterator as i1
/* 7 */ if (...) { i3.next(); /* CME not thrown */ }
// The following invalidates all iterators over v
/* 8 */ v.add("...");
/* 9 */ if (...) { i1.next(); /* CME thrown */ }
Figure 3: A Java program fragment illustrating CMP.

1 comment:

yogitechi said...

Synchronizing the methods of the class resolved this problem.

At least for time being.

Because when one method is modifing the other cannot read.

So no CME.

And the reference to the hashmap is not retuned from any of the methods. So only way to access it is through the synchronized methods.