代码之家  ›  专栏  ›  技术社区  ›  Dan

我可以从多个线程安全地查询具有xpath表达式的dom文档吗?

  •  3
  • Dan  · 技术社区  · 14 年前

    我计划在多线程可以查询文档的应用程序中使用dom4j dom文档作为静态缓存。 考虑到文档本身永远不会更改,从多个线程查询文档是否安全?

    我写了下面的代码来测试它,但我不确定它是否真的证明了操作是安全的?

        package test.concurrent_dom;
    
        import org.dom4j.Document;
        import org.dom4j.DocumentException;
        import org.dom4j.DocumentHelper;
        import org.dom4j.Element;
        import org.dom4j.Node;
    
        /**
         * Hello world!
         *
         */
        public class App extends Thread
        {
            private static final String xml = 
                "<Session>"
                    + "<child1 attribute1=\"attribute1value\" attribute2=\"attribute2value\">"
                    + "ChildText1</child1>"
                    + "<child2 attribute1=\"attribute1value\" attribute2=\"attribute2value\">"
                    + "ChildText2</child2>" 
                    + "<child3 attribute1=\"attribute1value\" attribute2=\"attribute2value\">"
                    + "ChildText3</child3>"
                + "</Session>";
    
            private static Document document;
    
            private static Element root;
    
            public static void main( String[] args ) throws DocumentException
            {
                document = DocumentHelper.parseText(xml);
                root = document.getRootElement();
    
                Thread t1 = new Thread(){
                    public void run(){
                        while(true){
    
                            try {
                                sleep(3);
                            } catch (InterruptedException e) {                  
                                e.printStackTrace();
                            }
    
                            Node n1 = root.selectSingleNode("/Session/child1");                 
                            if(!n1.getText().equals("ChildText1")){                     
                                System.out.println("WRONG!");
                            }
                        }
                    }
                };
    
                Thread t2 = new Thread(){
                    public void run(){
                        while(true){
    
                            try {
                                sleep(3);
                            } catch (InterruptedException e) {                  
                                e.printStackTrace();
                            }
    
                            Node n1 = root.selectSingleNode("/Session/child2");                 
                            if(!n1.getText().equals("ChildText2")){                     
                                System.out.println("WRONG!");
                            }
                        }
                    }
                };
    
                Thread t3 = new Thread(){
                    public void run(){
                        while(true){
    
                            try {
                                sleep(3);
                            } catch (InterruptedException e) {                  
                                e.printStackTrace();
                            }
    
                            Node n1 = root.selectSingleNode("/Session/child3");                 
                            if(!n1.getText().equals("ChildText3")){                     
                                System.out.println("WRONG!");
                            }
                        }
                    }
                };
    
                t1.start();
                t2.start();
                t3.start();
                System.out.println( "Hello World!" );
            }    
    
        }
    
    2 回复  |  直到 9 年前
        1
  •  5
  •   mdma    14 年前

    http://xerces.apache.org/xerces2-j/faq-dom.html

    不,dom不需要 实现是线程安全的。如果 您需要从访问DOM 多线程,需要 为您的 应用程序代码。

    如果没有看到实现,就不可能知道 selectSingleNode 使用任何共享状态来读取DOM。我认为假设它不是线程安全的是最安全的。

    另一种选择是使用您自己的XPath处理器,如Jaxen,它是线程安全的。

    xpath对象是完全可重入的,并且 线程安全。它们不包含内部 评估状态,因此可以 轻松缓存并在 应用。一旦你有了一个xpath 对象,您可以将其应用于 各种初始上下文和检索 结果有几种不同的方式: --- Introduction to SAX path and Jaxen

    JaxenJira对线程安全问题进行了各种修复,提供了Jaxen被设计为线程安全的证据。这是 one 我偶然遇到。 和 confirmation Jaxen是线程安全的,不会受到作者之一的攻击。

    Jaxen不仅是线程安全的,而且是模型不可知论者——它可以与许多模型(W3C DOM、XOM、DOM4J、JDOM)一起工作,并且可以通过实现几个接口插入自定义模型。

    我可以想象W3C DOM上的简单访问器和迭代器是线程安全的。但这只是一种预感,并不是一个具体的事实。如果你想100%确定,那么就使用一个专为线程安全而设计的DOM,例如, dom4j .

    要开始的一些资源: - An example of using Jaxen . - Jaxen FAQ homepage

        2
  •  0
  •   emory    14 年前

    我实际上并不熟悉dom4j dom,但是如果您不确定它是否能够正确地处理只读数据,我不确定它有多好。

    我将做一个操作假设,您的可执行文件的可执行部分(睡眠后的部分)需要不到一微秒的时间,并且在您的测试运行中,它们是连续发生的,而不是同时发生的。所以你的测试并不能证明什么。

    为了做一个更强大的测试,我

    1. 消除了3微秒的睡眠-您的测试代码应该忙于生成潜在的冲突,而不是睡眠。
    2. 增加线程数-并发执行线程越多,机会越大
    3. 添加了原始冲突检测

      final AtomicReference<Thread>owner=new AtomicReference<Thread>() ;
      class TestThread
      {
          private String url ;
          private String expected ;
          TestThread(int index) { url = "/Session/child" + i ; expected="ChildText" + i ; }
          public String toString () {return expected;}
          public void run()
          {
              while(true)
              {
                  boolean own=owner.compareAndSet(null,this);
                  Node n1 = root.selectSingleNode(url);                 
                  boolean wrong = !n1.getText().equals(result);
                  owner.compareAndSet(this,null);
                  if(!own) { System.out.println ( owner.get() + " conflicts " + this ) }
                  if(wrong){System.out.println(this + " WRONG!");
              }
          }
      }
      

      }

    然后

    try{
        while(true){
        Thread t1 = new TestThread(1);
        t1.start();
        Thread t2 = new TestThread(2);
        t2.start();
        Thread t3 = new TestThread(3);
        t3.start();
        }
    }
    catch(Throwable thr){
        thr.printStackTrace();
    }
    

    如果它按预期工作(这是未编译和未测试的),那么它将继续生成新线程,新线程将尝试读取文档。如果它们可能与另一个线程发生时间冲突,它们将报告。如果读取错误的值,它们将报告。它将不断生成新的线程,直到系统耗尽资源,然后它将崩溃。