Hi,<br><br>Our application uses JDOM (along with ROME), and spawns several threads to download RSS feeds. We utilize ROME custom modules, which use JDOM Namespace support. Sometimes, perhaps 1 in 15 launches, the XML parsing never finishes. Instead, all 4 cores on my machine are 100% loaded as HashMap.get() loops infinitely.<br>
<br>We tracked this down to the org.jdom.Namespace class. It has an "interesting" comment:<br><br> // XXX We may need to make the namespaces HashMap synchronized with<br> // reader/writer locks or perhaps make Namespace no longer a flyweight.<br>
// As written, multiple put() calls may happen from different threads <br> // concurrently and cause a ConcurrentModificationException. See<br> // <a href="http://lists.denveronline.net/lists/jdom-interest/2000-September/003009.html">http://lists.denveronline.net/lists/jdom-interest/2000-September/003009.html</a>.<br>
// No one has ever reported this over the many years, so don't worry yet.<br><br>Well, I'm reporting it. It does not cause ConcurrentModificationException, however. Instead, the map becomes corrupt and get() loops infinitely. Here is a stack trace from a thread dump taken using Sun's VisualVM:<br>
<br>"SwingWorker-pool-4-thread-1" prio=6 tid=0x11d1c800 nid=0x5c8 runnable [0x1186f000..0x1186fc68]<br> java.lang.Thread.State: RUNNABLE<br> at java.util.HashMap.get(Unknown Source)<br> at org.jdom.Namespace.getNamespace(Namespace.java:148)<br>
at org.jdom.Namespace.getNamespace(Namespace.java:202)<br> at com.sun.syndication.io.impl.ModuleParsers.parseModules(ModuleParsers.java:49)<br> at com.sun.syndication.io.impl.BaseWireFeedParser.parseFeedModules(BaseWireFeedParser.java:53)<br>
at com.sun.syndication.io.impl.Atom10Parser.parseFeed(Atom10Parser.java:177)<br> at com.sun.syndication.io.impl.Atom10Parser.parse(Atom10Parser.java:75)<br> at com.sun.syndication.io.WireFeedInput.build(WireFeedInput.java:252)<br>
at com.sun.syndication.io.SyndFeedInput.build(SyndFeedInput.java:161)<br> at coop.nisc.newsreader.impl.rome.RomeFeedProvider.getFeedFromAtom(RomeFeedProvider.java:87)<br> at coop.nisc.newsreader.impl.XmlIo.getEntriesFromXml(XmlIo.java:205)<br>
at coop.nisc.newsreader.impl.FileDataStore.loadFromDisk(FileDataStore.java:51)<br> at coop.nisc.newsreader.impl.FileDataStore.getViewEntries(FileDataStore.java:41)<br> - locked <0x0508ae58> (a coop.nisc.newsreader.impl.FileDataStore)<br>
at coop.nisc.newsreader.SubscriptionModel$GetInitialEntriesWorker.doInBackground(SubscriptionModel.java:331)<br> at coop.nisc.newsreader.SubscriptionModel$GetInitialEntriesWorker.doInBackground(SubscriptionModel.java:326)<br>
at javax.swing.SwingWorker$1.call(Unknown Source)<br> at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)<br> at java.util.concurrent.FutureTask.run(Unknown Source)<br> at javax.swing.SwingWorker.run(Unknown Source)<br>
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)<br> at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)<br> at java.lang.Thread.run(Unknown Source)<br><br>The app hangs on that HashMap.get() forever, as it loops infinitely, consuming all CPU.<br>
<br>The JDOM bug is that Namespace.java reads and writes to/from the HashMap class (private static HashMap namespaces;) without proper synchronization. Failure to synchronize on a HashMap is a well-known threading bug:<br>
<br><a href="http://lightbody.net/blog/2005/07/hashmapget_can_cause_an_infini.html">http://lightbody.net/blog/2005/07/hashmapget_can_cause_an_infini.html</a><br><br><br>I don't have a small test case (yet), but from a code review it looks as if synchronizing this method in Namespace.java will solve the issue:<br>
<br>public static Namespace getNamespace(String prefix, String uri) { ... }<br><br><br><br><br clear="all"><br>-- <br>Eric M. Burke<br><a href="http://www.linkedin.com/in/ericburke">http://www.linkedin.com/in/ericburke</a><br>
314-494-3185 (mobile)<br>636-272-3298 (home)<br>