Frage

Ich habe eine blockierende Warteschlange von Objekten.

Ich möchte einen Thread schreiben, der blockiert, bis ein Objekt in der Warteschlange steht. Ähnlich der von blockingqueue.take () bereitgestellten Funktionalität.

Da ich jedoch nicht weiß, ob ich das Objekt erfolgreich verarbeiten kann, möchte ich nur schauen () und das Objekt nicht entfernen. Ich möchte das Objekt nur entfernen, wenn ich es erfolgreich verarbeiten kann.

Ich möchte also eine blockierende Peek () -Funktion. Derzeit kehrt Peek () nur zurück, wenn die Warteschlange gemäß den Javadocs leer ist.

Vermisse ich etwas? Gibt es eine andere Möglichkeit, diese Funktionalität zu erreichen?

BEARBEITEN:

Irgendwelche Gedanken darüber, ob ich gerade eine threadere Warteschlange verwendet und stattdessen geschlafen habe?

public void run() {
    while (!exit) {
        while (queue.size() != 0) {
            Object o =  queue.peek();
            if (o != null) {
                if (consume(o) == true) {
                    queue.remove();
                } else {
                    Thread.sleep(10000); //need to backoff (60s) and try again
                }
            }
        }
        Thread.sleep(1000); //wait 1s for object on queue
    }
}

Beachten Sie, dass ich nur einen Verbraucher -Thread und einen (separaten) Produzenten -Thread habe. Ich denke, das ist nicht so effizient wie die Verwendung eines Blockingqueue ... alle Kommentare wurden geschätzt.

War es hilfreich?

Lösung

Sie könnten a verwenden Linked BlockingDeque und entfernen Sie das Element physisch aus der Warteschlange (Verwenden takeLast()) aber ersetzen Sie es erneut bei das Ende der Warteschlange Wenn die Verarbeitung nicht verwendet wird putLast(E e). In der Zwischenzeit würden Ihre "Produzenten" Elemente zu der hinzufügen Vorderseite der Warteschlange verwenden putFirst(E e).

Sie könnten dieses Verhalten immer in Ihrem eigenen verkapeln Queue Implementierung und Bereitstellung a blockingPeek() Methode, die ausgeführt wird takeLast() gefolgt von putLast() Hinter den Kulissen der zugrunde liegenden LinkedBlockingDeque. Aus der Sicht des aufrufenden Kunden wird das Element niemals aus Ihrer Warteschlange entfernt.

Andere Tipps

Da ich jedoch nicht weiß, ob ich das Objekt erfolgreich verarbeiten kann, möchte ich nur schauen () und das Objekt nicht entfernen. Ich möchte das Objekt nur entfernen, wenn ich es erfolgreich verarbeiten kann.

Im Allgemeinen ist es nicht fadensicher. Was wäre, wenn nach dir peek() und bestimmen Sie, dass das Objekt erfolgreich verarbeitet werden kann, aber vor Ihnen take() Um zu entfernen und zu verarbeiten, nimmt ein anderer Thread dieses Objekt?

Das einzige, was mir dessen bewusst ist, ist dies BlockingBuffer in Apache Commons -Sammlungen:

Wenn entweder das Get oder das Entfernen auf einem leeren Puffer gerufen wird, wartet der aufgerufene Thread auf die Benachrichtigung, dass ein Hinzufügen oder Addall -Betrieb abgeschlossen ist.

get() ist äquivalent zu peek(), und ein Buffer kann dazu gebracht werden, sich so zu verhalten BlockingQueue durch Dekoration a Unrundenfifobuffer mit einer BlockingBuffer

Könnten Sie auch nur eine Event -Hörer -Warteschlange zu Ihrer blockierenden Warteschlange hinzufügen, wenn die (blockierende) Warteschlange hinzugefügt wird, senden Sie eine Veranstaltung an Ihre Zuhörer? Sie könnten Ihren Threadblock haben, bis die actionPersformierte Methode aufgerufen wurde.

Die schnelle Antwort lautet, dass es nicht wirklich einen Weg gibt, einen blockierenden Blick auf die Bar zu haben, die eine blockierende Warteschlange mit einem blockierenden Peek () selbst implementiert.

Vermisse ich etwas?

peek () kann mit Parallelität problematisch sein -

  • Wenn Sie Ihre Peek () 'D -Nachricht nicht verarbeiten können, bleibt sie in der Warteschlange, es sei denn, Sie haben mehrere Verbraucher.
  • Wer wird dieses Objekt aus der Warteschlange herausholen, wenn Sie es nicht verarbeiten können?
  • Wenn Sie mehrere Verbraucher haben, erhalten Sie eine Rennbedingung zwischen Ihnen Peek () und einem anderen Thread, der auch Elemente verarbeitet, was zu einer doppelten Verarbeitung oder schlechterer Verarbeitung führt.

Klingt so, als ob Sie besser dran sind, den Artikel tatsächlich zu entfernen und es mit einem zu verarbeitenVerantwortungskette Muster

Bearbeiten: Betreff: Ihr letztes Beispiel: Wenn Sie nur einen Verbraucher haben, werden Sie das Objekt in der Warteschlange nie los Wahrscheinlich hätte den Artikel sowieso nicht in die Warteschlange setzen sollen.

Blockingqueue selbst hat nicht die Funktionalität, die Sie angeben.

Ich könnte versuchen, das Problem jedoch ein wenig neu zu gestalten: Was würden Sie mit Objekten tun, die Sie nicht "richtig verarbeiten" können? Wenn Sie sie nur in der Warteschlange lassen, müssen Sie sie irgendwann herausziehen und sich mit ihnen befassen. Ich würde entweder herausfinden, wie man sie verarbeitet Ein FIFO.

Keine Antwort an sich, aber: JDK-6653412 Behauptungen, dies sei kein gültiger Anwendungsfall.

Die "einfachste" Lösung

Verarbeiten die nicht nächste Element bis der früher Element wird erfolgreich verarbeitet.

public void run() {

Object lastSuccessfullyProcessedElement = null;

    while (!exit) {
        Object obj =  lastSuccessfullyProcessedElement == null ? queue.take() : lastSuccessfullyProcessedElement; // blocking

        boolean successful = process(obj);

        if(!successful) {
            lastSuccessfullyProcessedElement = obj;
        } else {
            lastSuccessfullyProcessedElement = null;
        }
    }
}
  1. Berufung peek() und überprüfen, ob der Wert Null ist, ist nicht CPU effizient.

Ich habe gesehen, wie die CPU -Nutzung auf 10% in meinem System wurde, wenn die Warteschlange für das folgende Programm leer ist.

while (true) {
   Object o = queue.peek();
   if(o == null) continue;
   // omitted for the sake of brevity
}
  1. Hinzufügen sleep() Fügt Langsamkeit hinzu.

  2. Addieren Sie es mit der Warteschlange mithilfe der Warteschlange zurück putLast wird die Bestellung stören. Darüber hinaus ist es ein Blockiervorgang, der Schlösser erfordert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top