浏览 1884 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-06-17
我们从JAXBContext这个对象开始,JAXBContext 是JAXB API的入口,典型的代码实现如下: private void unmarshal() { JAXBContext context = JAXBContext.newInstance(DirectoryConstants.JAXB_CONTEXT_CLASS); Unmarshaller u = context.createUnmarshaller(); Object obj = u.unmarshal(...); } 这个是标准使用流程了,首先初始化JAXBContext对象,通过JAXBContext对象创建Unmarshaller对象,然后使用Unmarshaller对象来进行unmarshal操作。 这个写法在功能实现上没有任何问题,但是如果一旦进行压力测试,就会暴露性能问题。JAXBContext对象的初始化是个资源消耗非常大的操作,我们可以通过threaddump进行分析,会发现很多工作线程都在执行JAXBContext.newInstance()这个方法,而不是我们期待的u.unmarshal()。而事实上JAXBContext对象的Sun实现是线程安全的,即容许多线程同时调用一个JAXBContext对象的createUnmarshaller(),因此完全没有必要为每个xml的 marshaling 和 unmarshalling 操作去初始化一次JAXBContext对象。可以参考这里的说明:https://jaxb.dev.java.net/faq/index.html#threadSafety 简单点说,这个一个初始化代价昂贵,却又可重复使用的对象。 因此,我们只需要初始化JAXBContext对象一次并保存起来,然后重复使用这个JAXBContext对象即可。保存JAXBContext对象的方式可以有很多种,比如cache / threadlocal,或者使用一个单例来维持这个对象。比如下面的代码示例: private void unmarshal() { JAXBContext context = JAXBContextHolder.get(); ... } public class JAXBContextHolder { private static final JAXBContext instance = JAXBContext.newInstance(DirectoryConstants.JAXB_CONTEXT_CLASS); public static JAXBContext get() { return instance; } } 在实际项目中, 通过上面的简单改进之后,我们当时得到了一个非常巨大的回报:TPS (transactions per second 每秒事务处理量)直接*3 !! 这个案例从技术上讲非常的简单,道理很浅显,相信每个人都能轻松理解。或者说,这是一个“知道了就简单,不知道就容易犯错而不自知”的地方,因此依然有些东西需要注意: (1) 有哪些对象有类似的特性 目前发现的类似对象有 1. 刚刚上面讲到的JAXB API中的 JAXBContext 对象 2. SOAP API中的javax.xml.soap.SOAPFactory 3. CFX client 通常情况下,在使用各种api或者工具类库时,如果发现调用代码中有类似的初始化语句,都应该稍加注意(除非明确当前代码对性能完全没有要求),可以去查一下这个类对象的javdoc或者直接看源码,如果发现满足上面所说的特性,则应该考虑进行上述的性能优化。 根据经验,类似的初始化对象通常的命名规则都是***Context/***Factory之类,或者***client,遇到类似名字时需要提高警惕。 (2)假设问题已经存在,如果才能在performance tuning中迅速发现问题的代码? 通常的办法就是用thread dump,一般连续dump个3-5次,然后通过分析thread dump信息 (推荐使用eclipse插件 lockness),看当前请求的线程(通常是一个线程池)都在干什么。一般初始化昂贵都昂贵在类似文件IO操作或者加锁之类的地方,很容易在thread dump中被发现。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |