Marshaller m = Jaxb.get(SomeClass.class).getMarshaller();
Unmarshaller um = Jaxb.get(SomeClass.class).getUnmarshaller();
你需要的代码是一个小的Jaxb类,如下所示:
public class Jaxb
{
// singleton pattern: one instance per class.
private static Map<Class,Jaxb> singletonMap = new HashMap<>();
private Class clazz;
// thread-local pattern: one marshaller/unmarshaller instance per thread
private ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<>();
private ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<>();
// The static singleton getter needs to be thread-safe too,
// so this method is marked as synchronized.
public static synchronized Jaxb get(Class clazz)
{
Jaxb jaxb = singletonMap.get(clazz);
if (jaxb == null)
{
jaxb = new Jaxb(clazz);
singletonMap.put(clazz, jaxb);
}
return jaxb;
}
// the constructor needs to be private,
// because all instances need to be created with the get method.
private Jaxb(Class clazz)
{
this.clazz = clazz;
}
/**
* Gets/Creates a marshaller (thread-safe)
* @throws JAXBException
*/
public Marshaller getMarshaller() throws JAXBException
{
Marshaller m = marshallerThreadLocal.get();
if (m == null)
{
JAXBContext jc = JAXBContext.newInstance(clazz);
m = jc.createMarshaller();
marshallerThreadLocal.set(m);
}
return m;
}
/**
* Gets/Creates an unmarshaller (thread-safe)
* @throws JAXBException
*/
public Unmarshaller getUnmarshaller() throws JAXBException
{
Unmarshaller um = unmarshallerThreadLocal.get();
if (um == null)
{
JAXBContext jc = JAXBContext.newInstance(clazz);
um = jc.createUnmarshaller();
unmarshallerThreadLocal.set(um);
}
return um;
}
}
7 回答
Note: 我是EclipseLink JAXB (MOXy)领导,是JAXB 2(JSR-222)专家组的成员 .
JAXBContext
是线程安全的,只应创建一次并重复使用,以避免多次初始化元数据的成本 .Marshaller
和Unmarshaller
不是线程安全的,但是要创建轻量级,并且可以按操作创建 .理想情况下,您应该有一个单独的
JAXBContext
和Marshaller
和Unmarshaller
的本地实例 .JAXBContext
实例是线程安全的,而Marshaller
和Unmarshaller
实例是 not 线程安全的,不应跨线程共享 .它在javadoc中具体描述了's a pity that this isn' . 我可以告诉你,Spring使用一个全局JAXBContext,在线程之间共享,而它为每个编组操作创建一个新的编组器,代码中的javadoc comment表示JAXB marshallers不一定是线程安全的 .
本页面的内容也是如此:http://jaxb.java.net/guide/Performance_and_thread_safety.html .
我猜想创建一个JAXBContext是一项代价高昂的操作,因为它涉及扫描类和注释的包 . 但测量它是最好的方法 .
我使用共享线程安全 JAXBContext 和线程本地 un/marschallers 解决了这个问题(因此理论上,将有与访问它们的线程一样多的 un/marshaller 实例),仅在 un/marshaller 的初始化时进行同步 .
JAXB 2.2(JSR-222)在第"4.2 JAXBContext"节中有这样的说法:
遗憾的是,该规范未对Unmarshaller和Marshaller的线程安全提出任何声明 . 所以最好假设它们不是 .
更好!!基于上面帖子中的好解决方案,在构造函数中只创建一次上下文,并保存它而不是类 .
替换线:
这一个:
和这个的主要构造函数:
所以在getMarshaller / getUnmarshaller中你可以删除这一行:
在我的情况下,这种改进使处理时间从60~70ms下降到仅5~10ms
我通常使用
ThreadLocal
类模式来解决这样的问题 . 鉴于您需要为每个类使用不同的编组器,您可以将其与singleton
-map模式组合 .为你节省15分钟的工作量 . 以下是我对Jaxb Marshallers和Unmarshallers的线程安全工厂的实现 .
它允许您按如下方式访问实例...
你需要的代码是一个小的Jaxb类,如下所示: