2009-03-21 3 views
0

Ich habe eine Producer-App, die einen Index generiert (speichert es in einigen In-Memory-Baum Datenstruktur). Und eine Verbraucher-App wird den Index verwenden, um nach Teilübereinstimmungen zu suchen.Design einer Producer/Consumer App

Ich möchte nicht, dass die Consumer UI (z. B. über einen Fortschrittsbalken) blockieren muss, während der Producer die Daten indiziert. Grundsätzlich, wenn der Benutzer den Teilindex verwenden möchte, wird es dies tun. In diesem Fall muss der Produzent möglicherweise für eine Weile die Indizierung stoppen, bis der Benutzer zu einem anderen Bildschirm wechselt.

Grob gesagt weiß ich, dass ich das wait/notify-Protokoll benötigen wird, um dies zu erreichen. Meine Frage: Ist es möglich, den Producer-Thread mit wait/notify zu unterbrechen, während er seinen Aufgaben nachgeht? Mit welchen java.util.concurrent-Primitiven muss ich das erreichen?

Antwort

0

In Ihrem Producer-Thread haben Sie wahrscheinlich eine Art Hauptschleife. Dies ist wahrscheinlich der beste Ort, um Ihren Produzenten zu unterbrechen. Statt Warte mit() und notify() Ich schlage vor, Sie in Java eingeführt Synchronisationsobjekte java verwenden 5.

Sie möglicherweise etwas wie das

class Indexer { 

    Lock lock = new ReentrantLock();  

    public void index(){ 
     while(somecondition){ 
      this.lock.lock(); 
      try{ 
       // perform one indexing step 
      }finally{ 
       lock.unlock(); 
      } 
     } 
    } 

    public Item lookup(){ 
     this.lock.lock(); 
     try{ 
      // perform your lookup 
     }finally{ 
      lock.unlock(); 
     } 
    } 
} 

Sie müssen

tun könnte, um sicherzustellen, dass jedes Mal, wenn die Indexer gibt die Sperre frei, Ihr Index befindet sich in einem konsistenten, legalen Status. Wenn der Indexer in diesem Szenario die Sperre freigibt, bleibt eine neue oder wartende lookup() -Operation übrig, um die Sperre zu übernehmen, abzuschließen und die Sperre aufzuheben. Anschließend kann der Indexer mit dem nächsten Schritt fortfahren.Wenn derzeit kein lookup() wartet, greift Ihr Indexer nur auf die Sperre selbst zu und geht mit der nächsten Operation weiter.

Wenn Sie der Meinung sind, dass mehr als ein Thread versucht, die Suche gleichzeitig durchzuführen, sollten Sie sich die ReadWriteLock-Schnittstelle und die ReentrantReadWriteLock-Implementierung ansehen.

Natürlich ist diese Lösung der einfache Weg, es zu tun. Es wird einen der Threads blockieren, die nicht über die Sperre verfügen. Vielleicht möchten Sie überprüfen, ob Sie Ihre Datenstruktur direkt synchronisieren können, aber das könnte sich als schwierig erweisen, da der Aufbau von Indizes dazu neigt, eine Art ausgeglichener Baum oder B-Baum zu verwenden oder wo die Knoteneinfügung bei weitem nicht trivial ist.

Ich schlage vor, dass Sie zuerst diesen einfachen Ansatz versuchen, dann sehen, ob die Art, wie es sich verhält, Ihnen passt. Wenn dies nicht der Fall ist, versuchen Sie entweder, die Indexierungsschritte in kleinere Schritte aufzuteilen oder versuchen Sie, nur Teile Ihrer Datenstruktur zu synchronisieren.

Mach dir keine Sorgen über die Leistung der Sperrung, in Java unüberlegtes Sperren (wenn nur ein Thread versucht, die Sperre zu nehmen) ist billig. Solange der Großteil Ihrer Sperrung nicht gesichert ist, ist die Sperrperformance unbedenklich.

2

Wie Sie dies beschrieben haben, gibt es keinen Grund, dass Sie warten/benachrichtigen müssen. Synchronisieren Sie einfach den Zugriff auf Ihre Datenstruktur, um sicherzustellen, dass sie sich beim Zugriff in einem konsistenten Zustand befindet.

Edit: von "Synchronize Access", ich meine nicht die gesamte Datenstruktur zu synchronisieren (was würde entweder Hersteller oder Verbraucher blockieren). Synchronisieren Sie stattdessen nur die Bits, die aktualisiert werden, und nur zu dem Zeitpunkt, zu dem Sie sie aktualisieren. Sie werden feststellen, dass die meisten Arbeiten des Herstellers unsynchronisiert ablaufen können. Wenn Sie beispielsweise einen Baum erstellen, können Sie den Knoten identifizieren, an dem der Einschub ausgeführt werden soll, auf diesem Knoten synchronisieren, den Einfügevorgang ausführen. dann weitermachen.

+0

Sie schlagen etwas vor, das dem Zeilensperren in Datenbanken ähnlich ist. Derzeit ist der Baum gesperrt, damit ein Thread durchlaufen werden kann. –

0

Die Producer-Anwendung kann zwei Indizes haben: published und in-work. Der Produzent wird nur mit in Arbeit arbeiten, der Verbraucher wird nur mit veröffentlichtem arbeiten. Sobald der Produzent mit der Indexierung fertig ist, kann er die Arbeit mit der veröffentlichten ersetzen (normalerweise wird ein Zeiger ausgetauscht). Der Produzent kann auch eine Kopie des Teilindex veröffentlichen, wenn er Wert bringt. Auf diese Weise vermeiden Sie langfristige Sperren - es wird nützlich sein, wenn der Index durch den Verlust von Verbrauchern abgerufen wird.

0

Nein, das ist nicht möglich.

Die einzige Möglichkeit, einen Thread ohne expliziten Code im Thread selbst zu melden, ist die Verwendung von Thread.interrupt(), was eine Ausnahme im Thread verursacht. interrrupt() ist normalerweise nicht sehr zuverlässig, da das Auslösen einer Ausnahme an einem beliebigen Punkt im Code ein Albtraum ist, um in allen Codepfaden richtig zu funktionieren. Daneben könnte ein einzelner Versuch {} catch (Throwable) {} irgendwo im Thread (einschließlich aller Bibliotheken, die Sie verwenden) ausreichen, um das Signal zu verschlingen.

In den meisten Fällen ist die einzige korrekte Lösung die Verwendung eines gemeinsamen Kennzeichens oder einer Warteschlange, die der Benutzer zum Übergeben von Nachrichten an den Hersteller verwenden kann. Wenn Sie sich darüber Sorgen machen, dass der Hersteller nicht reagiert oder nicht reagiert, führen Sie ihn in einem separaten Thread aus und fordern Sie ihn auf, alle n Sekunden Heartbeat-Nachrichten zu senden. Wenn es keinen Herzschlag sendet, töte es. (Beachten Sie, dass es oft sehr schwer ist, zu bestimmen, ob ein Produzent tatsächlich einfriert und nicht nur auf ein externes Ereignis wartet).

+0

Hier gibt es einige gute Ideen, aber es gibt auch einige Fehler. Das Unterbrechen eines Threads wird * nicht * eine Ausnahme auslösen "an einem zufälligen Punkt". InterruptedExceptions werden überprüft, und Methoden, die sie auslösen können, sind gut definiert. Schlecht geschriebene "Catch-All" -Blöcke reichen aus, um ein Programm zu unterbrechen. – erickson

+0

Ihr Vorschlag über die Warteschlange ist ziemlich interessant. Was ich tun könnte, ist, dass der Producer alle 10 Baumknoten, die verarbeitet werden, auf die Anfrage des Konsumenten prüft. Ich bin nur sicher, dass dies auf den Benutzer reagiert. –

Verwandte Themen