4 Stimmen

austauschbarer Arbeitsvorrat

Es gibt einen Namen dafür, aber ich weiß nicht, wie er lautet, und es ist schwer, ihn zu googeln.

Was ich suche, ist etwas in der Java-Concurrency-Utilities, die ein Paar von Warteschlangen ist, eine "Pending"-Warteschlange, die von einem Produzenten verwendet wird, und eine "Processing"-Warteschlange, die von einem Verbraucher verwendet wird, wo der Verbraucher die Warteschlangen atomar austauschen kann. Wenn sie auf diese Weise verwendet werden (1 Producer-Thread, 1 Consumer-Thread), müssen die einzelnen Warteschlangen nicht thread-sicher sein, sondern nur die Verweise auf sie.

Ich weiß, dass ich das schon einmal irgendwo gesehen habe, und ich kann so etwas wahrscheinlich auch selbst zusammenschustern, aber wenn es schon existiert, würde ich lieber das verwenden.

bearbeiten: Ich schätze, das Primitive, das ich suche, ist ein Paar von atomaren Referenzen, die atomar ausgetauscht werden können. (& Ich kann die Warteschlangen selbst hinzufügen.)


bearbeiten 2: @Alex Miller beantwortete die quälende Frage, an was ich dachte, mich aber nicht erinnern konnte. Das löst mein Problem jedoch nicht, da es sich um eine Fadensperre handelt und ich möchte, dass der Hersteller nicht blockieren muss.

Was ich wollte, war, dass in dem Moment, in dem der Konsument beginnt, Elemente aus der Warteschlange abzurufen und zu verarbeiten, alle diese Elemente der Warteschlange vollständig sein müssen und der Produzent danach keine Elemente mehr hinzufügen kann; der Produzent muss nun Elemente zur anderen Warteschlange hinzufügen. Der gepaarte/vertauschte Satz atomarer Referenzen wird also nicht funktionieren.

(Das ist so, als ob es zwei Schulbusse gibt, von denen einer immer auf Fahrgäste wartet und der andere sie immer woanders hinbringt. Sobald der Fahrer wegfährt, ist es vorbei, man muss in den anderen Bus einsteigen. Wenn man Referenzen hat, können die Hersteller den Bus betreten, obwohl er schon weg ist, was nicht erlaubt ist).

Ich denke, ich werde stattdessen eine einzelne ConcurrentLinkedQueue und haben einen Sentinel-Wert, den der Verbraucher der Warteschlange hinzufügt. Damit kann es nicht nur einen, sondern mehrere Produzenten geben. Damit der Konsument Stapel von Elementen in der Warteschlange verarbeiten kann, wartet er, bis sich mindestens ein Element in der Warteschlange befindet, fügt dann den Sentinel am Ende der Warteschlange ein und entfernt Elemente, bis der Sentinel entfernt wird. Dann tut der Verbraucher, was immer er zwischen den Stapeln zu tun hat. Das ist das Verhalten, das ich wollte.

Es muss nicht unbedingt ein garantiert blockierungsfreier Ansatz sein (Sperren oder synchronized Methoden sind Optionen), aber wenn es einen einfachen Weg gibt, es so zu gestalten, dass es so ist, dann ist das in meiner Anwendung vorzuziehen.

2voto

Alex Miller Punkte 67243

2voto

sfossen Punkte 4704

Eine Warteschlange mit Lese-/Schreibsperre ist wahrscheinlich eine bessere Idee. Denn, wenn Sie sonst atomar in eine lokale Warteschlange kopieren müssten.

Denn es gäbe ein Synchronisationsproblem, wenn man die Referenzen vertauscht, während man liest/löscht oder schreibt.

RWLock würde mehrere Verbraucher/Erzeuger zulassen.

Gibt es einen Grund, warum Sie sich von RWLocks fernhalten möchten?

Wie bei jeder Verriegelung sollte die Sperre so kurz wie möglich gehalten werden, um ein Aushungern zu verhindern.

oder etwas Ähnliches für den Austausch von Daten verwenden. Wobei jeder Thread seine eigene Warteschlange hat.

 class LockedQueue
 {
    private final List<Data>  q = new ArrayList<Data>();
    private final Lock lock = new ReentrantLock();

    public void get( List<Data> consumerQ ) {
        if( lock.tryLock() ) { try { consumerQ .addAll( q ); q.clear(); } finally { lock.unlock(); }}
    }
    public Data put( List<Data> producerQ ) {
        if( lock.tryLock() ) { try { return q.addAll( producerQ  ); producerQ .clear(); } finally { lock.unlock(); }}
    }
    public void clear() {
        lock.lock(); try { q.clear(); } finally { lock.unlock(); }
    }
 }

mit dem Verbraucher, der get() aufruft, wenn er leer ist oder am Ende jeder Schleife, und dem Verbraucher, der put aufruft, nachdem er so viele Elemente oder Zeit oder ... hinzugefügt hat.

0voto

Ben S Punkte 66945

Es gibt keine Datenstruktur mit den doppelten Warteschlangen, wie Sie sie beschreiben, sondern die gleichzeitige Hilfsmittel haben viele verschiedene Warteschlangen, aus denen sie eine auswählen können.

Das von Ihnen beschriebene Problem ist allerdings sehr häufig, ich hatte irgendwie erwartet, dass ich auch eines finden würde. Vielleicht in Java 1.7.

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