Frage

Ich habe das klassische Problem, dass ein Thread Ereignisse in die eingehende Warteschlange eines zweiten Threads drückt. Nur dieses Mal interessiere ich mich sehr für Leistung. Was ich erreichen möchte ist:

  • Ich möchte den gleichzeitigen Zugriff auf die Warteschlange, den Produzenten, den Empfänger, Poping.
  • Wenn die Warteschlange leer ist, möchte ich, dass der Verbraucher die Warteschlange blockiert und auf den Produzenten wartet.

Meine erste Idee war, a zu verwenden LinkedBlockingQueue, aber ich erkannte bald, dass es nicht gleichzeitig ist und die Leistung erlitten hat. Andererseits benutze ich jetzt a ConcurrentLinkedQueue, aber trotzdem zahle ich die Kosten von wait() / notify() Bei jeder Veröffentlichung. Da der Verbraucher bei der Suche nach einer leeren Warteschlange nicht blockiert wird, muss ich synchronisieren und wait() Auf einem Schloss. Andererseits muss der Produzent das Schloss bekommen und notify() Bei jeder einzelnen Veröffentlichung. Das Gesamtergebnis ist, dass ich die Kosten von zahlesycnhronized (lock) {lock.notify()} In jeder einzelnen Veröffentlichung, auch wenn nicht erforderlich.

Was ich hier denke, ist hier eine Warteschlange, die sowohl blockiert als auch gleichzeitig ist. Ich stelle mir a vor push() Betrieb wie in ConcurrentLinkedQueue, mit einem extra notify() zum Objekt, wenn das Pushed -Element das erste in der Liste ist. Ein solcher Scheck, den ich für bereits in der vorliegt ConcurrentLinkedQueue, wie das Pushing, muss eine Verbindung mit dem nächsten Element hergestellt werden. Dies wäre also viel schneller als jedes Mal auf der externen Schloss zu synchronisieren.

Ist so etwas so verfügbar/vernünftig?

War es hilfreich?

Lösung

Ich denke, Sie können sich festhalten java.util.concurrent.LinkedBlockingQueue Unabhängig von Ihren Zweifel. Es ist gleichzeitig. Ich habe jedoch keine Ahnung von seiner Leistung. Wahrscheinlich andere Umsetzung von BlockingQueue passen besser zu dir. Es gibt nicht zu viele von ihnen, also machen Sie Leistungstests und messen Sie.

Andere Tipps

Ähnlich wie diese Antwort https://stackoverflow.com/a/1212515/1102730 aber ein bisschen anders .. Ich habe eins verwendet ExecutorService. Sie können eine durch Verwendung eines Instanziierens instanziieren Executors.newSingleThreadExecutor(). Ich brauchte eine gleichzeitige Warteschlange zum Lesen/Schreiben von PufferedImages in Dateien sowie Atomizität mit Lese- und Schreibvorgängen. Ich brauche nur einen einzelnen Thread, da die Datei -IO Größenordnungen schneller ist als die Quelle Net IO. Außerdem war ich mehr besorgt über Atomizität von Aktionen und Korrektheit als über die Leistung, aber dieser Ansatz kann auch mit mehreren Fäden im Pool durchgeführt werden, um die Dinge zu beschleunigen.

Um ein Bild zu erhalten (Versuch, final weggelassen):

Future<BufferedImage> futureImage = executorService.submit(new Callable<BufferedImage>() {
    @Override
        public BufferedImage call() throws Exception {
            ImageInputStream is = new FileImageInputStream(file);
            return  ImageIO.read(is);
        }
    })

image = futureImage.get();

So speichern Sie ein Bild (Versuch-Catch-final weggelassen):

Future<Boolean> futureWrite = executorService.submit(new Callable<Boolean>() {
    @Override
    public Boolean call() {
        FileOutputStream os = new FileOutputStream(file); 
        return ImageIO.write(image, getFileFormat(), os);  
    }
});

boolean wasWritten = futureWrite.get();

Es ist wichtig zu beachten, dass Sie Ihre Streams in einem endgültigen Block spülen und schließen sollten. Ich weiß nicht, wie es im Vergleich zu anderen Lösungen funktioniert, aber es ist ziemlich vielseitig.

Ich würde vorschlagen, dass Sie sich ansehen Threadpoolexecutor NewsinglethreadExecutor. Es wird es erfüllen, Ihre für Sie bestellten Aufgaben zu halten, und wenn Sie sich einreichen Hallables Für Ihren Testamentsvollstrecker können Sie auch das Blockierungsverhalten erhalten, das Sie suchen.

Sie können LinkedTransferqueue von JSR166 ausprobieren: http://gee.cs.oswego.edu/cgi-ner/viewcvs.cgi/jsr166/src/jsr166y/

Es erfüllt Ihre Anforderungen und enthält weniger Overhead für Angebots-/Umfrageoperationen. Wie ich aus dem Code sehen kann, verwendet die Warteschlange, wenn sie nicht leer ist, atomare Operationen für Wahlelemente. Und wenn die Warteschlange leer ist, dreht sie sich für einige Zeit und parkt den Faden, falls erfolglos. Ich denke, es kann in Ihrem Fall helfen.

Ich benutze das ArrayBlockingQueue, wenn ich Daten von einem Thread an einen anderen weitergeben muss. Verwenden der Put- und Nehmenmethoden (die blockieren, wenn sie voll/leer sind).

Hier ist ein Liste der implementierenden Klassen BlockingQueue.

Ich würde empfehlen, sich zu überprüfen SynchronousQueue.

Wie @rorick in seinem Kommentar erwähnt, glaube ich, dass alle diese Implementierungen gleichzeitig sind. Ich denke, Ihre Bedenken sind mit LinkedBlockingQueue kann fehl am Platz sein.

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