2010-05-28 13 views
3

다중 스레드가 문서를 쿼리 할 수있는 응용 프로그램에서 dom4j DOM Document를 정적 캐시로 사용할 계획입니다. 문서 자체가 절대로 변경되지 않는다는 사실을 고려하면 여러 스레드에서 문서를 쿼리하는 것이 안전합니까?여러 스레드의 xpath 표현식을 사용하여 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!"); 
     }  

    } 

답변

5

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

번호 DOM 스레드 안전을 위해 구현을 필요로하지 않습니다 말한다. 여러 스레드에서 DOM에 액세스해야하는 경우 응용 프로그램 코드에 적절한 잠금을 추가해야합니다.

구현을 보지 않고 selectSingleNode이 DOM을 읽는 데 공유 상태를 사용하는지 여부를 알 수 없습니다. 스레드로부터 안전하지 않다고 가정하는 것이 가장 안전하다고 생각합니다.

대신 스레드로부터 안전한 Jaxen과 같은 XPath 프로세서를 사용하는 것이 좋습니다.

XPath 개체는 완전히 재진입이고 스레드로부터 안전합니다. 평가를 위해 내부에 상태가 없으므로 을 쉽게 캐시하고 응용 프로그램 내에서 공유 할 수 있습니다.당신이하는 XPath 객체가 있으면, 당신은 다양한 초기 상황에 적용하고 여러 가지 방법으로 결과를 검색 할 수 있습니다 를 --- Introduction to SAX path and Jaxen

JAXEN 락스가 제공하는 스레드 안전 문제에 대한 다양한 수정이 Jaxen은 스레드로부터 안전하도록 설계된 증거입니다. 이것은 one 내가 우연히 우연히 만났습니다. confirmation Jaxen은 작성자 중 한 명으로부터 스레드로부터 안전합니다.

Jaxen은 스레드로부터 안전 할뿐만 아니라 모델에 구애받지 않습니다. 여러 모델 (W3C DOM, XOM, Dom4J, JDOM)에서 작동하며 몇 가지 인터페이스를 구현하여 사용자 정의 모델을 연결할 수 있습니다.

W3C DOM의 간단한 액세서와 반복기가 스레드로부터 안전하다고 생각합니다. 그러나 이것은 단지 직감이며 구체적인 사실이 아닙니다. 100 % 확실하게하려면 thread-saftey 용으로 설계된 DOM을 사용하십시오 (예 : dom4j).

시작하기위한 몇 가지 리소스 : - An example of using Jaxen. - Jaxen FAQhomepage

0

실제로 DOM4J DOM에 익숙하지 않지만 읽기 전용 데이터를 제대로 처리 할 수 ​​있는지 확실하지 않은 경우 얼마나 좋은지 잘 모르겠습니다.

나는 runnables의 실행 부분 (sleep 후 부분)이 1 microsecond보다 적게 소요된다는 것을 조작 상으로 가정 할 것이고, 당신의 테스트 run에서 그것들은 동시에 발생하지 않고 연속적으로 발생했다. 따라서 귀하의 테스트는 실제로 아무것도 증명하지 않습니다. 보다 강력한 테스트를 위해

, 나는

  1. 는 3 마이크로 잠을 제거 - 테스트 코드 자고, 잠재적 인 충돌을하지 생성 바쁜해야합니다. 더 동시에 실행되는 스레드,
  2. 이 경우

다음 원시 충돌 감지

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(); 
} 

을 추가 한 더 기회 -

  • 스레드 수를 증가 예측대로 작동합니다 (uncompi입니다. led 및 untested) 새 스레드를 계속 생성하면 새 스레드는 문서를 읽으려고 시도합니다. 잠재적으로 다른 스레드와 시간이 충돌하는지보고합니다. 그들은 잘못된 값을 읽었는지보고 할 것입니다. 시스템에서 자원이 다할 때까지 새로운 스레드를 생성 한 다음 충돌합니다.