Wie verwende ich ein ConcurrentLinkedQueue
in Java?
Muss LinkedQueue
ich mir dabei Sorgen um die Parallelität in der Warteschlange machen? Oder muss ich nur zwei Methoden definieren (eine zum Abrufen von Elementen aus der Liste und eine zum Hinzufügen von Elementen zur Liste)?
Hinweis: Natürlich müssen diese beiden Methoden synchronisiert werden. Richtig?
BEARBEITEN: Ich versuche Folgendes zu tun: Ich habe eine Klasse (in Java) mit einer Methode zum Abrufen von Elementen aus der Warteschlange und eine andere Klasse mit einer Methode zum Hinzufügen von Elementen zur Warteschlange. Die Elemente, die hinzugefügt und aus der Liste abgerufen werden, sind Objekte meiner eigenen Klasse.
Noch eine Frage: Muss ich dies in der Methode remove tun?
while (queue.size() == 0){
wait();
queue.poll();
}
Ich habe nur einen Verbraucher und einen Produzenten.
quelle
Antworten:
Nein, die Methoden müssen nicht synchronisiert werden, und Sie müssen keine Methoden definieren. Sie befinden sich bereits in ConcurrentLinkedQueue. Verwenden Sie sie einfach. ConcurrentLinkedQueue führt alle Sperr- und sonstigen Operationen aus, die Sie intern benötigen. Ihre Produzenten fügen Daten in die Warteschlange ein und Ihre Konsumenten fragen danach ab.
Erstellen Sie zunächst Ihre Warteschlange:
Übergeben Sie nun, wo immer Sie Ihre Produzenten- / Konsumentenobjekte erstellen, die Warteschlange, damit sie irgendwo ihre Objekte ablegen können (Sie könnten stattdessen einen Setter dafür verwenden, aber ich bevorzuge es, solche Dinge in einem Konstruktor zu tun):
und:
und füge Sachen in deinem Produzenten hinzu:
und nehmen Sie Sachen in Ihrem Verbraucher heraus (wenn die Warteschlange leer ist, gibt poll () null zurück, also überprüfen Sie es):
Weitere Informationen finden Sie im Javadoc
BEARBEITEN:
Wenn Sie das Warten blockieren müssen, bis die Warteschlange nicht leer ist, möchten Sie wahrscheinlich eine LinkedBlockingQueue verwenden und die Methode take () verwenden. LinkedBlockingQueue hat jedoch eine maximale Kapazität (standardmäßig Integer.MAX_VALUE, die über zwei Milliarden beträgt) und kann daher je nach Ihren Umständen angemessen sein oder auch nicht.
Wenn nur ein Thread Inhalte in die Warteschlange stellt und ein anderer Thread Inhalte aus der Warteschlange entfernt, ist ConcurrentLinkedQueue wahrscheinlich übertrieben. Dies ist eher der Fall, wenn Hunderte oder sogar Tausende von Threads gleichzeitig auf die Warteschlange zugreifen. Ihre Bedürfnisse werden wahrscheinlich erfüllt durch:
Ein Plus davon ist, dass die Instanz (Warteschlange) gesperrt wird, sodass Sie in der Warteschlange synchronisieren können, um die Atomizität zusammengesetzter Operationen sicherzustellen (wie von Jared erläutert). Sie können dies NICHT mit einer ConcurrentLinkedQueue tun, da alle Vorgänge OHNE Sperren der Instanz ausgeführt werden (unter Verwendung der Variablen java.util.concurrent.atomic). Sie müssen dies NICHT tun, wenn Sie blockieren möchten, während die Warteschlange leer ist, da poll () einfach null zurückgibt, während die Warteschlange leer ist, und poll () atomar ist. Überprüfen Sie, ob poll () null zurückgibt. Wenn dies der Fall ist, warten Sie () und versuchen Sie es erneut. Keine Notwendigkeit zu sperren.
Schließlich:
Ehrlich gesagt würde ich nur eine LinkedBlockingQueue verwenden. Es ist immer noch übertrieben für Ihre Anwendung, aber die Chancen stehen gut, dass es gut funktionieren wird. Wenn es nicht performant genug ist (PROFIL!), Können Sie immer etwas anderes ausprobieren, und es bedeutet, dass Sie sich nicht mit synchronisierten Dingen befassen müssen:
Alles andere ist das gleiche. Put wird wahrscheinlich nicht blockiert, da Sie wahrscheinlich nicht zwei Milliarden Objekte in die Warteschlange stellen.
quelle
Collection.synchronizedList
eine zurückgegeben,List
die nicht implementiert wirdQueue
.ConcurrentLinkedQueue
für Producer Consumer eine gute Idee, ich beziehe mich auf diesen Beitrag stackoverflow.com/questions/1426754/…Dies ist größtenteils ein Duplikat einer anderen Frage .
Hier ist der Abschnitt dieser Antwort, der für diese Frage relevant ist:
Muss ich meine eigene Synchronisation durchführen, wenn ich java.util.ConcurrentLinkedQueue verwende?
Atomare Operationen für die gleichzeitigen Sammlungen werden für Sie synchronisiert. Mit anderen Worten, jeder einzelne Aufruf der Warteschlange ist garantiert threadsicher, ohne dass Sie etwas unternehmen müssen. Was nicht garantiert threadsicher ist, sind alle Operationen, die Sie an der Sammlung ausführen und die nicht atomar sind.
Dies ist beispielsweise threadsicher, ohne dass Sie etwas unternehmen müssen:
oder
Jedoch; Nicht-atomare Aufrufe der Warteschlange sind nicht automatisch threadsicher. Beispielsweise sind die folgenden Vorgänge nicht automatisch threadsicher:
Letzteres ist nicht threadsicher, da es sehr wahrscheinlich ist, dass zwischen dem Aufruf von isEmpty und dem Aufruf der Zeitabfrage andere Threads Elemente zur Warteschlange hinzugefügt oder daraus entfernt haben. Der threadsichere Weg, dies durchzuführen, ist folgender:
Wieder ... atomare Aufrufe der Warteschlange sind automatisch threadsicher. Nichtatomare Anrufe sind es nicht.
quelle
Verwenden Sie poll , um das erste Element abzurufen, und add , um ein neues letztes Element hinzuzufügen. Das war's, keine Synchronisation oder irgendetwas anderes.
quelle
Dies ist wahrscheinlich das, wonach Sie in Bezug auf Thread-Sicherheit und "Hübschheit" suchen, wenn Sie versuchen, alles in der Warteschlange zu verbrauchen:
Dies garantiert, dass Sie beenden, wenn die Warteschlange leer ist, und dass Sie weiterhin Objekte aus der Warteschlange entfernen, solange sie nicht leer ist.
quelle
Die ConcurentLinkedQueue ist eine sehr effiziente Implementierung ohne Warten / Sperren (siehe Javadoc als Referenz). Sie müssen also nicht nur nicht synchronisieren, sondern die Warteschlange sperrt auch nichts und ist somit praktisch so schnell wie eine nicht synchronisierte (kein Thread) sicher) eins.
quelle
Verwenden Sie es einfach wie eine nicht gleichzeitige Sammlung. Die Concurrent [Collection] -Klassen umschließen die regulären Sammlungen, sodass Sie nicht über die Synchronisierung des Zugriffs nachdenken müssen.
Bearbeiten: ConcurrentLinkedList ist nicht nur ein Wrapper, sondern eine bessere gleichzeitige Implementierung. In beiden Fällen müssen Sie sich keine Gedanken über die Synchronisierung machen.
quelle