Details
-
Bug
-
Status: Resolved
-
Critical
-
Resolution: Invalid
-
Version 2.3, Version 2.3.1
-
None
-
None
-
Microsoft Windows XP [Version 5.1.2600], single-core
java version "1.5.0_10"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_10-b03)
Java HotSpot(TM) Client VM (build 1.5.0_10-b03, mixed mode)
Description
When setting a property on many XmlBeans objects with a single large variable, all threads concerned will block with this stacktrace:
java.lang.Object.wait:-2
java.lang.Object.wait:-1
org.apache.xmlbeans.impl.common.Mutex.acquire:33
org.apache.xmlbeans.impl.common.GlobalLock.acquire:27
org.apache.xmlbeans.impl.values.XmlObjectBase.set:1944
The test below sets a Type on it's Document and illustrates the problem. I can't publish the actual schema and namespace, but to give an idea of size, the XML object is about 90 KB of complex data (multiple namespaces, hundreds of elements, embedded CDATA).
A workaround has been included in commented-out form.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.xmlbeans.XmlException;
import tests.LargeDataStructureType;
import tests.LargeDataStructureDocument;
public class BlockingExample {
public static void main(String[] args) throws InterruptedException, XmlException, IOException {
LargeDataStructureDocument doc = LargeDataStructureDocument.Factory.parse(new File("exampleFile.xml"));
LargeDataStructureType type = doc.getLargeDataStructureType();
List<Setter> setters = new ArrayList<Setter>();
for(int i = 0; i != 20; i++) setters.add(new Setter(key));
for(Setter s : setters) s.start();
Thread.sleep(10000);
Map<Thread,StackTraceElement[]> map=Thread.getAllStackTraces();
for(Thread t:map.keySet()){
StackTraceElement[] ss=map.get(t);
System.out.println("Thread:"t.getName()":"t.getState()":"+t.isAlive());
if(ss!=null) {
for(StackTraceElement s:ss)
}
}
System.exit(0);
}
}
class Setter extends Thread {
private static int counter = 0;
private LargeDataStructureType type;
Setter(LargeDataStructureType type)
{ /* * This reproduces the behaviour */ this.type = type; /* * This also reproduces the behaviour */ // this.type = (LargeDataStructureType)type.copy(); /* * This is a reliable workaround. */ // this.type = LargeDataStructureType.Factory.newInstance(); // type.set(type); } public void run() {
while(true) {
LargeDataStructureDocument obj = LargeDataStructureDocument.Factory.newInstance();
obj.setLargeDataStructure(key);
if(counter++ % 10000 == 0)
{ System.out.print("."); } }
}
}
This produces the following output:
.Thread:Thread-7:WAITING:true
java.lang.Object.wait:-2
java.lang.Object.wait:-1
org.apache.xmlbeans.impl.common.Mutex.acquire:33
org.apache.xmlbeans.impl.common.GlobalLock.acquire:27
org.apache.xmlbeans.impl.values.XmlObjectBase.set:1944
tests.LargeDataStructureTypeImpl.setLargeDataStructure:xx
be.inglease.wel.Setter.run:64
Thread:Thread-13:WAITING:true
java.lang.Object.wait:-2
java.lang.Object.wait:-1
org.apache.xmlbeans.impl.common.Mutex.acquire:33
org.apache.xmlbeans.impl.common.GlobalLock.acquire:27
org.apache.xmlbeans.impl.values.XmlObjectBase.set:1944
tests.LargeDataStructureTypeImpl.setLargeDataStructure:xx
be.inglease.wel.Setter.run:64
(...etc. for 20 threads)
The expected output would just be lots of dots followed by various stacktraces.