3 Stimmen

Kann ich DOM-Dokument mit xpath-Ausdruck von mehreren Threads sicher abfragen?

Ich plane, dom4j DOM-Dokument als statischen Cache in einer Anwendung zu verwenden, wo mehrere Threads das Dokument abfragen können. Unter Berücksichtigung der Tatsache, dass das Dokument selbst wird nie ändern, ist es sicher, es von mehreren Threads abfragen?

Ich habe den folgenden Code geschrieben, um ihn zu testen, aber ich bin mir nicht sicher, ob er tatsächlich beweist, dass der Vorgang sicher ist?

    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!" );
        }    

    }

6voto

mdma Punkte 55529

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

Nein. DOM erfordert keine Implementierungen thread-sicher zu sein. Wenn Sie von mehreren Threads auf das DOM zugreifen müssen mehreren Threads zugreifen müssen, sind Sie verpflichtet die entsprechenden Sperren zu Ihrer Anwendungscode hinzufügen.

Ohne die Umsetzung zu sehen, ist es unmöglich zu wissen, ob selectSingleNode verwendet einen gemeinsamen Zustand zum Lesen des DOM. Ich denke, es ist am sichersten, anzunehmen, dass es nicht Thread-sicher ist.

Eine Alternative ist die Verwendung eines eigenen XPath-Prozessors, wie z. B. Jaxen, der thread-sicher ist.

XPath-Objekte sind vollständig reentrant und thread-sicher. Sie enthalten keinen internen Zustand für die Auswertung und können daher problemlos zwischengespeichert und innerhalb einer Anwendung gemeinsam genutzt werden. Sobald Sie ein XPath Objekt haben, können Sie es gegen verschiedenen Ausgangskontexten anwenden und die Ergebnisse auf verschiedene Weise abrufen: --- Einführung in SAX-Pfad und Jaxen

Im JAXEN Jira finden sich verschiedene Fixes für thread-sichere Probleme, die belegen, dass Jaxen thread-sicher konzipiert ist. Dies ist eine Ich bin zufällig darauf gestoßen. Und Bestätigung dass Jaxen thread-safe ist, von einem der Autoren.

Jaxen ist nicht nur thread-sicher, sondern auch modellunabhängig - es funktioniert mit vielen Modellen (W3C DOM, XOM, Dom4J, JDOM) und benutzerdefinierte Modelle können durch die Implementierung einiger Schnittstellen hinzugefügt werden.

Ich könnte mir vorstellen, dass einfache Accessoren und Iteratoren auf dem W3C DOM thread-sicher sind. Aber das ist nur eine Vermutung und keine konkrete Tatsache. Wenn Sie 100 % sicher sein wollen, dann verwenden Sie ein DOM, das für Thread-Safety entwickelt wurde, zum Beispiel, dom4j .

Einige Ressourcen für den Einstieg: - Ein Beispiel für die Verwendung von Jaxen . - Jaxen FAQ y Homepage

0voto

emory Punkte 10495

Ich bin eigentlich nicht vertraut mit dom4j DOM, aber wenn Sie nicht sicher sind, dass es ordnungsgemäß mit schreibgeschützten Daten umgehen kann, bin ich nicht sicher, wie gut es ist.

Ich gehe davon aus, dass der ausführbare Teil Ihrer Runnables (der Teil nach dem sleep) weniger als eine Mikrosekunde dauert und dass sie in Ihrem Testlauf nacheinander und nicht gleichzeitig ablaufen. Ihr Test beweist also nicht wirklich etwas.

Für einen robusteren Test, I

  1. die 3 Mikrosekunden Schlafzeit eliminiert - Ihr Testcode sollte damit beschäftigt sein, potentielle Konflikte zu erzeugen, und nicht schlafen.
  2. die Anzahl der Threads erhöht - je mehr Threads gleichzeitig ausgeführt werden, desto größer ist die Chance
  3. Primitive Konflikterkennung hinzugefügt

    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!");
            }
        }
    }

    }

dann

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

Wenn es wie vorhergesagt funktioniert (dies ist unkompiliert und ungetestet), dann werden immer wieder neue Threads erzeugt, die dann versuchen, das Dokument zu lesen. Sie melden, wenn sie möglicherweise in einen Zeitkonflikt mit einem anderen Thread geraten. Sie werden melden, wenn sie einen falschen Wert lesen. Es werden so lange neue Threads erzeugt, bis Ihr System keine Ressourcen mehr hat, dann wird es abstürzen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X