[jdom-interest] ConcurrentModificationException
Alex Rosen
arosen at silverstream.com
Thu Mar 28 10:43:21 PST 2002
I've attached a quick writeup of the relevent change in beta 8. Hopefully
this should explain things. I don't know what your PageMap or Template
classes are, but I assume that the PageMap.addTemplate() method is adding a
child to the parent Element, so you're running into this problem.
Jason, do you want to add something along these lines to the FAQ, and/or
some kind of upgrade document? (I haven't actually tried the code I wrote
here, but it looks OK.)
--Alex
In JDOM beta 7, methods such as getContent() aka getMixedContent(),
getChildren(), and getAttributes() all returned instances of PartialList.
This list did not fulfill the JDOM contract of these methods, because it was
only partially "live". Changes made to the PartialList were reflected in the
underlying Element or Document, but not vice versa. In JDOM beta 8,
PartialList is replaced by the more correct and more efficient FilterList.
Now, the returned list is fully live, so it will see change made to the
underlying Element or Document as soon as they happen. As Jason says in the
changelog:
"Added the long-awaited 'FilterList' functionality! This improves the
reliability and performance of the lists returned by getContent() and
getChildren() calls. These lists are now fully live, they fully enforce
well-formedness constraints, and they don't require in-memory copying before
returning. A huge improvement!"
An important change in the behavior of these lists involves Iterators.
FilterList has the same iterator contract as the standard Java ArrayList and
LinkedList classes:
"The iterators returned by the this class's iterator and listIterator
methods are 'fail-fast': if the list is structurally modified at any time
after the iterator is created, in any way except through the Iterator's own
remove or add methods, the iterator will throw a
ConcurrentModificationException. Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than risking
arbitrary, non-deterministic behavior at an undetermined time in the
future."
Note that this can happen even for single-threaded applications. For
example, this code worked in beta 7 will no longer work in beta 8.
// Remove children whose name starts with the given prefix.
public void removePrefix(Element parent, String prefix)
{
Iterator iter = parent.getChildren().iterator();
while (iter.hasNext())
{
Element child = (Element)iter.next();
if(child.getName().startsWith(prefix))
{
parent.removeContent(child);
}
}
}
This code will throw a ConcurrentModificationException, because the list of
children is being changed from outside of the Iterator, while the Iterator
is still being used.
The simple fix is to use the methods on Iterator or ListIterator to do the
modification - use add(), remove(), or set(). In this example, just change
"parent.removeContent(child)" to "iter.remove()".
Another technique would be to create a non-live list from the live list. For
example, use this line:
List staticList = new ArrayList(parent.getChildren());
This creates a new ArrayList containing the children of the Element, but
this list is static; it will not change when the parent Element changes
(and, changes to this list will not affect the parent).
> -----Original Message-----
> From: jdom-interest-admin at jdom.org
> [mailto:jdom-interest-admin at jdom.org]On Behalf Of Garrett Zork
> Sent: Thursday, March 28, 2002 1:41 AM
> To: jdom-interest at jdom.org
> Subject: [jdom-interest] ConcurrentModificationException
>
>
> I've gotten a ConcurrentModificationException in my code. Can
> someone share the main reasons for getting this Exception?
>
> I eliminated the error by grabbing my List from Jaxen rather
> than JDOM, though, this is obviously not my preferred solution.
>
> I'm running JDOM b8 (and Jaxen- beta 8)
>
> I'm not using threads, and didn't "remove" anything from
> the List - either through the iterator or outside of the iterator.
> I would certainly like to know the JDOM programming constructs
> to avoid.
> ---------------------------------
> Snippet of offending code: (sorry for the linewrap)
>
> //List templateList=sectionElement.getChildren("template");
> //This JDOM List fails
>
> List templateList=UtilXML.getXpathResults(sectionElement,"template");
> //This (convenience method) Jaxen List succeeds
>
> Iterator templateIter=templateList.iterator();
>
> int pageCount=0;
> while (templateIter.hasNext()) { //This is line 78:
> where the exception occurs
> pageCount++;
> PageMap myPageMap= new PageMap(section);
>
> for (int i=0;(i<sectionColumnCount &&
> templateIter.hasNext());i++) {
> for (int j=0;(j<sectionRowCount &&
> templateIter.hasNext());j++) {
> Element templateElement=(Element) templateIter.next();
> Template myTemplate= new Template(templateElement);
> myPageMap.addTemplate(myTemplate, i, j);
> }
> }
> myPageMap.writePageToDocument(sectionElement,pageCount);
> }
>
> -------------------------------------
> here's the stacktrace:
>
> java.util.ConcurrentModificationException
> at
> org.jdom.ContentList$FilterListIterator.checkConcurrentModific
> ation(ContentList.java:1206)
> at
> org.jdom.ContentList$FilterListIterator.hasNext(ContentList.java:928)
> at ig.CatalogBuilder.buildSection(CatalogBuilder.java:78)
> at ig.CatalogBuilder.<init>(CatalogBuilder.java:65)
> at ig.TestCatalogBuilder.main(TestCatalogBuilder.java:24)
> Exception in thread "main"
>
More information about the jdom-interest
mailing list