JAXB creating context and marshallers cost

53,191

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");
        }
    }
}
Share:
53,191
Vladimir
Author by

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, 2020

Comments

  • Vladimir
    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
    Vladimir over 12 years
    Hi @JB, great answer especially your comments on measuring and why JAXBContext is costly.
  • Vladimir
    Vladimir over 12 years
    great answer. I can be confident now based on your experience as lead on JAXB.
  • Vladimir
    Vladimir over 12 years
    thanks for the answer. Unfortunately I have to select only one answer :-)
  • Hurda
    Hurda over 10 years
    I trust you, but is this to be found somewhere in documentation?
  • ymajoros
    ymajoros over 10 years
    ThreadLocal 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
    ymajoros over 10 years
    ThreadLocal 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
    Aydin Gerek over 9 years
    It's documented for the RI: jaxb.java.net/guide/Performance_and_thread_safety.html (but not Moxy AFAIK)
  • Thomas W
    Thomas W almost 9 years
    Javadoc 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
    Thomas W almost 9 years
    Please specify this in the Javadoc. It's not satisfactory to have these crucial aspects undocumented.
  • John
    John almost 9 years
    How big was the xml file you were parsing. Do you see significant improvement with very large xml files?
  • tbarderas
    tbarderas over 8 years
    it'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
    Reg Whitton over 7 years
    It 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
    Vlasec almost 6 years
    @Caoilte user guide was moved to javaee.github.io/jaxb-v2/doc/user-guide/…
  • MauganRa
    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
    MauganRa over 4 years
    You 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
    Anurag Reddy over 3 years
    Could you add some text answering the OP's questions also.
  • Vijay Varma
    Vijay Varma over 3 years
    @AnuragReddy Done, pls check
  • zmx
    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
    Lii almost 3 years
    ThreadLocal#initialValue should not be synchronised here. It uses only the thread safe JAXBContext object.