我正在查看的当前代码库使用 DOM 解析器。以下代码片段在 5 个方法中重复:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
如果在循环中调用包含上述代码的方法,或者在应用程序中多次调用该方法,我们将承担为每次调用此类方法创建一个新的 DocumentBuilderFactory 实例和一个新的 DocumentBuilder 实例的开销。
围绕 DocumentBuilder 工厂和 DocumentBuilder 实例创建一个单例包装器是否是个好主意,如下所示:
public final class DOMParser {
private DocumentBuilderFactory = new DocumentBuilderFactory();
private DocumentBuilder builder;
private static DOMParser instance = new DOMParser();
private DOMParser() {
builder = factory.newDocumentBuilder();
}
public Document parse(InputSource xml) {
return builder.parser(xml);
}
}
如果跨多个线程共享上述单例,是否会出现任何问题?如果不是,通过使用上述方法在应用程序的整个生命周期中只创建一次 DocumentBuilderFactory 和 DocumentBuilder 实例,是否会有任何性能提升?
编辑 :
我们唯一会遇到的问题是,如果 DocumentBuilder 在解析 XML 文件时保存了一些状态信息,这可能会影响下一个 XML 文件的解析。
原文由 Chetan Kinger 发布,翻译遵循 CC BY-SA 4.0 许可协议
有关同一问题的其他问题,请参阅评论部分。 对你的问题的简短回答:不, 将这些类放在一个单例中是不行的。 DocumentBuilderFactory 和 DocumentBuilder 都不能保证是线程安全的。如果您有多个线程解析 XML,请确保每个线程都有自己的 DoumentBuilder 版本。每个线程只需要其中一个,因为您可以在重置后重用 DocumentBuilder。
编辑 一个小片段来表明使用相同的 DocumentBuilder 是不好的。对于 java 1.6_u32 和 1.7_u05,此代码失败并显示
org.xml.sax.SAXException: FWK005 parse may not be called while parsing
。取消对构建器同步的注释,它工作正常:所以这是你的答案 - 不要从多个线程调用
DocumentBuilder.parse()
。是的,这种行为可能是特定于 JRE 的,如果您使用的是 IBM java 或 JRockit 或者给它一个不同的 DocumentBuilderImpl,它可能工作正常,但对于默认的 xerces 实现 - 它不会。