JAXB creating context and marshallers cost
Solution 1
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
JAXBContext
is thread safe and should only be created once and reused to avoid the cost of initializing the metadata multiple times. Marshaller
and Unmarshaller
are not thread safe, but are lightweight to create and could be created per operation.
Solution 2
Ideally, you should have a singleton JAXBContext
and local instances of Marshaller
and Unmarshaller
.
JAXBContext
instances are thread-safe while Marshaller
and Unmarshaller
instances are not thread-safe and should never be shared across threads.
Solution 3
It's a pity that this isn't specifically described in the javadoc. What I can tell is that Spring uses a global JAXBContext, shared between threads, whereas it creates a new marshaller for each marshalling operation, with a javadoc comment in the code saying that JAXB marshallers are not necessarily thread-safe.
The same is said on this page:https://javaee.github.io/jaxb-v2/doc/user-guide/ch03.html#other-miscellaneous-topics-performance-and-thread-safety.
I would guess that creating a JAXBContext is a costly operation, because it involves scanning classes and packages for annotations. But measuring it is the best way to know.
Solution 4
JAXB 2.2 (JSR-222) has this to say, in section "4.2 JAXBContext":
To avoid the overhead involved in creating a
JAXBContext
instance, a JAXB application is encouraged to reuse a JAXBContext instance. An implementation of abstract class JAXBContext is required to be thread-safe, thus, multiple threads in an application can share the same JAXBContext instance.[..]
JAXBContext class is designed to be immutable and thus threadsafe. Given the amount of dynamic processing that potentially could take place when creating a new instance of JAXBContxt, it is recommended that a JAXBContext instance be shared across threads and reused as much as possible to improve application performance.
Unfortunately, the specification does not make any claims regarding thread-safety of Unmarshaller
and Marshaller
. So it is best to assume they are not.
Solution 5
I solved this problem using:
- shared thread safe JAXBContext and thread local un/marschallers
- (so theoretically, there will be as many un/marshaller instances as there are threads which accessed them)
- with synchronization only on un/marshaller's initialization.
public class MyClassConstructor {
private final ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<Unmarshaller>() {
protected synchronized Unmarshaller initialValue() {
try {
return jaxbContext.createUnmarshaller();
} catch (JAXBException e) {
throw new IllegalStateException("Unable to create unmarshaller");
}
}
};
private final ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<Marshaller>() {
protected synchronized Marshaller initialValue() {
try {
return jaxbContext.createMarshaller();
} catch (JAXBException e) {
throw new IllegalStateException("Unable to create marshaller");
}
}
};
private final JAXBContext jaxbContext;
private MyClassConstructor(){
try {
jaxbContext = JAXBContext.newInstance(Entity.class);
} catch (JAXBException e) {
throw new IllegalStateException("Unable to initialize");
}
}
}
Vladimir
I am continuously thinking about making development more quick, more declarative, straightforward and more human-friendly. Currently I am working on a little great product for end-user consumers which works on PC and Mac and developed mostly using Java.
Updated on September 11, 2020Comments
-
Vladimir over 3 years
The question is a bit theoretical, what is the cost of creating JAXB context, marshaller and unmarshaller?
I've found that my code could benefit from keeping the same JAXB context and possibly the same marshaller for all marshaling operations rather than creating context and marshaller on each marshaling.
So what is the cost of creating JAXB context and marshaller/unmarshaller? Is it okay to create context+marshaller for each marshaling operation or it's better to avoid it?
-
Vladimir over 12 yearsHi @JB, great answer especially your comments on measuring and why JAXBContext is costly.
-
Vladimir over 12 yearsgreat answer. I can be confident now based on your experience as lead on JAXB.
-
Vladimir over 12 yearsthanks for the answer. Unfortunately I have to select only one answer :-)
-
Hurda over 10 yearsI trust you, but is this to be found somewhere in documentation?
-
ymajoros over 10 yearsThreadLocal will introduce other subtile problems, without benefit. Just keep a single JAXBContext (that's the costly part) and create a new Unmarshaller whenever required.
-
ymajoros over 10 yearsThreadLocal will introduce other subtile problems, without benefit. Just keep a single JAXBContext (that's the costly part) and create a new Unmarshaller whenever required.
-
Aydin Gerek over 9 yearsIt's documented for the RI: jaxb.java.net/guide/Performance_and_thread_safety.html (but not Moxy AFAIK)
-
Thomas W almost 9 yearsJavadoc has always been weak on the crucial facts of lifecycle. It sure gives us trivial repetition of property getters & setters, but as to knowing how/where to get or create an instance, mutation & thread-safety.. it seems to completely miss those most-important factors. Sigh :)
-
Thomas W almost 9 yearsPlease specify this in the Javadoc. It's not satisfactory to have these crucial aspects undocumented.
-
John almost 9 yearsHow big was the xml file you were parsing. Do you see significant improvement with very large xml files?
-
tbarderas over 8 yearsit's not really a matter of big xml files (mines goes from just 2-3kb up to +6mb) , but instead a matter of a very large number of xml files (we're talking here of about 10,000 xml requests per minute); in that case creating the context just once gaining those little ms makes a huge difference
-
Reg Whitton over 7 yearsIt isn't mentioned in the Javadoc that JAXBContext is thread safe. And just about every example of how to use JAXB, fails to mention that it should be created once and shared across threads. As a result I'm now removing yet another howling resource leak from a live system. Grrrrrrr.
-
Vlasec almost 6 years@Caoilte user guide was moved to javaee.github.io/jaxb-v2/doc/user-guide/…
-
MauganRa over 4 years@Reg Whiton it's not just a resource leak. At work we found out that concurrent accesses can mess up the Marshaller internally and later cause unreproducible ArrayIndexOutOfBounds exceptions during marshalling. The proplem would persist until restarting the app. At least we realized this before going production...
-
MauganRa over 4 yearsYou actually don't need separate JAXBContexts since you can pass in multiple classes. So, if you can predict which classes are going to be marshalled, you can create a single shared one. Also, the JAXB spec requires them to be threadsafe already.
-
Anurag Reddy over 3 yearsCould you add some text answering the OP's questions also.
-
Vijay Varma over 3 years@AnuragReddy Done, pls check
-
zmx almost 3 years"Marshaller and Unmarshaller [...] are lightweight to create and could be created per operation" - this might be misleading, according to the docs: "creating Unmarshaller could be relatively an expensive operation" for multiple small docs. javaee.github.io/jaxb-v2/doc/user-guide/ch06.html
-
Lii almost 3 years
ThreadLocal#initialValue
should not be synchronised here. It uses only the thread safeJAXBContext
object.