JDK-6660724 : Lock Contention in SAX2DOM()
  • Type: Bug
  • Component: xml
  • Sub-Component: org.w3c.dom
  • Affected Version: 1.4.2_25
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_10
  • CPU: x86
  • Submitted: 2008-02-07
  • Updated: 2012-04-25
  • Resolved: 2008-05-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6 JDK 7
1.4.0 1.4Fixed 6u14Fixed 7Fixed
Lock contention while running web service tests to analyze the performance of JCAPS. The web service is a very simple EJB that echoes the request back as the response. The JStack output is given below. 

"httpSSLWorkerThread-8080-58" daemon prio=3 tid=0x0a406000 nid=0x1e0 waiting for monitor entry [0x2c654000..0x2c6559f0]
  java.lang.Thread.State: BLOCKED (on object monitor)
       at com.sun.org.apache.xalan.internal.xsltc.trax.SAX2DOM.<init>(SAX2DOM.java:68)
       - waiting to lock <0x3730c410> (a java.lang.Class for com.sun.org.apache.xalan.internal.xsltc.trax.SAX2DOM)
       at com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory.getSerializationHandler(TransletOutputHandlerFactory.java:187)
       at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.getOutputHandler(TransformerImpl.java:392)
       at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerHandlerImpl.setResult(TransformerHandlerImpl.java:137)
       at com.sun.xml.bind.v2.runtime.unmarshaller.DomLoader$State.<init>(DomLoader.java:74)
       at com.sun.xml.bind.v2.runtime.unmarshaller.DomLoader.startElement(DomLoader.java:113)
       at com.sun.xml.bind.v2.runtime.unmarshaller.XsiTypeLoader.startElement(XsiTypeLoader.java:73)
       at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:449)
       at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:427)
       at com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:71)
       at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.handleStartElement(StAXStreamConnector.java:275)
       at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:209)
       at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:358)
       at com.sun.xml.bind.v2.runtime.BridgeImpl.unmarshal(BridgeImpl.java:120)
       at com.sun.xml.bind.api.Bridge.unmarshal(Bridge.java:233)
       at com.sun.xml.ws.message.stream.StreamMessage.readPayloadAsJAXB(StreamMessage.java:229)

EVALUATION An additional fix has been added based upon Jitu's suggestion. The fix is to futher improve performance for the default JDK implementation by caching the DocumentBuilder.

EVALUATION The JavaDoc for DocumentBuilderFactory was not explicit wrt thread safety. However, that in the JAXP 1.4 RI/JDK6 internal implementation is. A patch has been provided to avoid the lock when the internal implementation is used. This patch is now available in JAXP 1.4 RI and will be requested to be considered for JDK6 integration.

EVALUATION I don't think having a property makes sense. In general, the right thing should just happen automatically, and in this case, it can. I read Santiago's evaluation and he has a point that while SAX2DOM class itself is not user visible, the DOM created by it is indeed user visible. So my next suggestion is, check if the _factory variable is a factory from the JAXP RI, and if so, create a new instance without a lock. Otherwise, do it with a lock. You can do this by checking a property, or the 'instanceof' operator. The check can be done upfront only once to avoid per invocation overhead, if that's helpful. A slightly better approach is for you to write a delegating DocumentBuilderFactory that calls another DocumentBuilderFactory and hides this detail there, but that's up to you.

EVALUATION Comments from Santiago: I think this may be possible, but it makes JAXP a bit less flexible. The SAX2DOM class is producing the output of a transformation (with DOMResult). The way it is implemented now, you can plug in whichever DOM implementation you like, and then downcast or do whatever you want with it. I'm not saying this is desirable, but it is possible. If we change this to use our internal DOM, then we should probably have to change this in many other places. In general, JAXP goes through the pluggability layer to allow people to use their SAX, DOM, etc. For the reason stated above, someone could argue this change is not backward compatible too. On the other hand, there are clear performance advantages in implementing the suggestion and in general avoiding the pluggability layer. It's a difficult one. Comment from Norm: we should use the plugability layer because that's what gives programmers the ability to plug in their own code.

SUGGESTED FIX Kohsuke had the following comments about the problem -> public SAX2DOM() throws ParserConfigurationException { synchronized (SAX2DOM.class) { _document = _factory.newDocumentBuilder().newDocument(); } _root = _document; } In JAXP RI, "newDocumentBuilder().newDocument()" is thread-safe, so synchronization can be removed. _factory should be also initialized with the "new XYZ" (where XYZ is the DocumentBuilderFactoryImpl in JAXP RI), instead of DocumentBuilderFactory.newInstance(), so that you know you are always using the JAXP RI for this.