如何以线程安全和有效的方式使用XPath?

时间:2019-01-03 16:38:08

标签: java multithreading xpath

(这里曾提出类似的问题Java XPathFactory thread-safety,但给出的答案是错误的,因为它忽略了文档指出XPathFactory.newInstance()并非线程安全的事实。)

XPathFactory Javadoc中,我们有:

  

XPathFactory类不是线程安全的。换句话说,它是   应用程序负责确保最多一个线程是   在任何给定时刻使用XPathFactory对象。实现是   鼓励将方法标记为同步,以保护自己免受   破碎的客户。

     

XPathFactory不是可重入的。而newInstance方法之一   正在被调用,应用程序可能不会尝试递归调用   newInstance方法,甚至来自同一线程。

因此,从上面的引用中,我认为不应同时调用XPathFactory.newInstance()(静态方法)。它不是线程安全的。

工厂返回XPath对象,该对象具有以下XPath Javadoc

  

XPath对象不是线程安全的,也不是可重入的。换一种说法,   应用程序有责任确保一个XPath   在任何给定的时间都没有从多个线程使用对象,并且   在调用评估方法时,应用程序可能不会递归   调用评估方法。

从上面的引用中,我认为不应XPath.evaluateXPathExpression.evaluate同时调用。它们不是线程安全的。

通常,当我处理不是线程安全的类时,我只使用局部变量,但是由于XPathFactory.newInstance()不是线程安全的,并且它是静态方法,因此我不确定如何安全有效地使用它。我想我可以同步对newInstance的调用,但是我担心性能,因为我的应用程序是XML消息路由应用程序。 (在我对newInstance的烟雾测试中,大约需要0.4毫秒。)

我找不到以线程安全的方式使用Java XPath的任何示例,而且我不确定我知道如何以线程安全的但有效的方式使用XPath。还有一个约束,我需要在单例(特别是Apache Camel Processor)内部使用XPath。

3 个答案:

答案 0 :(得分:3)

您可以放弃JAXP / DOM领域,而转而使用Saxon,在那里将多线程更仔细地整合到API设计中:

  • 与DOM不同,一旦文档构建完成,Saxon本机树实现是线程安全的。您还将获得XPath 3.1作为奖励。

  • 使用设置程序方法配置XPathCompiler后,它是线程安全的

  • XPathExpression(通过使用XPathCompiler编译表达式来创建)是线程安全的(可以在多个线程中同时执行)

  • XPathSelector(通过加载XPathExpression形成)不是线程安全的;只能评估一次。

答案 1 :(得分:2)

  

我认为XPathFactory.newInstance()(静态方法)不应同时被调用。它不是线程安全的。

该文档的解释可能有所不同:线程安全性和可重入性是不同的属性,因此XPathFactory.newInstance()可能是线程安全的,但不可重入。 递归一词似乎很关键;但是句子结构很难解析。如果不仔细检查代码,则围绕任何newInstance调用的同步似乎是使用它们的唯一安全方法。请注意,Java 9添加了newDefaultInstance方法,该方法似乎是线程安全的。

  

我认为XPath.evaluateXPathExpression.evaluate不应同时被调用。它们不是线程安全的。

同意。文档明确指出这些方法既不是线程安全的也不是可重入的。

答案 2 :(得分:0)

文档似乎集中于对象,而不是newInstance调用。这是您引用的部分;我增加了一些重点:

  

XPathFactory类不是线程安全的。换句话说,应用程序负责确保在任何给定时刻最多有一个线程正在使用 XPathFactory对象

并且:

  

XPath对象不是线程安全的,也不是可重入的。

请注意,它引用的是现有对象。 XPathFactory.newInstance是静态方法;它是静态方法。它不能在现有的XPathFactory对象上运行。在调用它的时刻,没有对象可以在线程之间共享。

文档指出,现有XPath和XPathFactory对象的非静态方法不是线程安全的。并不是说您不能在不同的线程中创建它们,只是说您不能在不同的线程中使用对象(除非您通过同步或锁定来保护该用法)。

更新:“在调用newInstance方法之一时,应用程序可能不会尝试递归调用newInstance方法”可能是指并发XPathFactory.newInstance调用,但我认为“递归”的存在表示特定的newInstance调用可能不会调用对newInstance的另一个调用。从理论上讲,如果您使用工厂类的名称来调用three-argument newInstance method,而工厂类本身会尝试调用newInstance。