Aus den JavaDocs:
- Eine ConcurrentLinkedQueue ist eine geeignete Wahl, wenn viele Threads gemeinsam auf eine gemeinsame Sammlung zugreifen. Diese Warteschlange erlaubt keine Nullelemente.
- ArrayBlockingQueue ist ein klassischer "begrenzter Puffer", in dem ein Array mit fester Größe Elemente enthält, die von Produzenten eingefügt und von Verbrauchern extrahiert wurden. Diese Klasse unterstützt eine optionale Fairness-Richtlinie für die Bestellung wartender Produzenten- und Konsumententhreads
- LinkedBlockingQueue hat normalerweise einen höheren Durchsatz als Array-basierte Warteschlangen, aber in den meisten gleichzeitigen Anwendungen eine weniger vorhersehbare Leistung.
Ich habe zwei Szenarien, eine erfordert, dass die Warteschlange viele Produzenten (Threads, die sie verwenden) mit einem Verbraucher unterstützt, und die andere ist umgekehrt.
Ich verstehe nicht, welche Implementierung ich verwenden soll. Kann jemand erklären, was die Unterschiede sind?
Was ist die "optionale Fairness-Richtlinie" in der ArrayBlockingQueue
?
java
multithreading
concurrency
queue
David Hofmann
quelle
quelle
Antworten:
Grundsätzlich besteht der Unterschied zwischen ihnen in den Leistungsmerkmalen und im Blockierverhalten.
Am einfachsten
ArrayBlockingQueue
ist zunächst eine Warteschlange mit fester Größe. Wenn Sie also die Größe auf 10 setzen und versuchen, ein 11. Element einzufügen, wird die insert-Anweisung blockiert, bis ein anderer Thread ein Element entfernt. Das Fairness-Problem besteht darin, was passiert, wenn mehrere Threads gleichzeitig versuchen, sie einzufügen und zu entfernen (dh während des Zeitraums, in dem die Warteschlange blockiert wurde). Ein Fairness-Algorithmus stellt sicher, dass der erste Thread, der fragt, der erste Thread ist, der abgerufen wird. Andernfalls kann ein bestimmter Thread länger warten als andere Threads, was zu unvorhersehbarem Verhalten führt (manchmal dauert ein Thread nur einige Sekunden, da andere Threads, die später gestartet wurden, zuerst verarbeitet wurden). Der Nachteil ist, dass die Verwaltung der Fairness einen Overhead erfordert und den Durchsatz verlangsamt.Der wichtigste Unterschied zwischen
LinkedBlockingQueue
undConcurrentLinkedQueue
besteht darin, dassLinkedBlockingQueue
Ihr Thread wartet, bis etwas vorhanden ist, wenn Sie ein Element von a anfordern und die Warteschlange leer ist. AConcurrentLinkedQueue
kehrt sofort mit dem Verhalten einer leeren Warteschlange zurück.Welches davon abhängt, ob Sie die Blockierung benötigen. Wo Sie viele Produzenten und einen Verbraucher haben, klingt es so. Wenn Sie dagegen viele Verbraucher und nur einen Hersteller haben, benötigen Sie möglicherweise nicht das Blockierungsverhalten und lassen die Verbraucher möglicherweise nur prüfen, ob die Warteschlange leer ist, und fahren fort, wenn dies der Fall ist.
quelle
ConcurrentLinkedQueue bedeutet, dass keine Sperren genommen werden (dh keine synchronisierten (dies) oder Lock.lock- Aufrufe). Bei Änderungen wird eine CAS-Compare- und Swap- Operation verwendet, um festzustellen, ob der Head / Tail-Knoten noch derselbe ist wie zu Beginn. Wenn ja, ist die Operation erfolgreich. Wenn der Kopf / Schwanz-Knoten unterschiedlich ist, dreht er sich und versucht es erneut.
LinkedBlockingQueue sperrt vor jeder Änderung. Ihre Angebotsanrufe würden also blockiert, bis sie die Sperre erhalten. Sie können die Angebotsüberladung verwenden, die eine TimeUnit benötigt, um zu sagen, dass Sie nur X Zeit warten möchten, bevor Sie das Hinzufügen abbrechen (normalerweise gut für Warteschlangen vom Nachrichtentyp, bei denen die Nachricht nach X Millisekunden veraltet ist).
Fairness bedeutet, dass die Lock-Implementierung die geordneten Threads beibehält. Das heißt, wenn Thread A und dann Thread B eintreten, erhält Thread A zuerst die Sperre. Ohne Fairness ist es wirklich undefiniert, was passiert. Es wird höchstwahrscheinlich der nächste Thread sein, der geplant wird.
Welche verwendet werden soll, hängt davon ab. Ich neige dazu, ConcurrentLinkedQueue zu verwenden, da meine Produzenten unterschiedliche Zeit benötigen, um Arbeit in die Warteschlange zu stellen. Ich habe nicht viele Produzenten, die genau im selben Moment produzieren. Die Verbraucherseite ist jedoch komplizierter, da die Umfrage nicht in einen guten Schlafzustand übergeht. Damit müssen Sie selbst umgehen.
quelle
In Ihrem Fragentitel wird das Blockieren von Warteschlangen erwähnt. Ist
ConcurrentLinkedQueue
jedoch keine blockierende Warteschlange.Die
BlockingQueue
s sindArrayBlockingQueue
,DelayQueue
,LinkedBlockingDeque
,LinkedBlockingQueue
,PriorityBlockingQueue
, undSynchronousQueue
.Einige davon sind eindeutig nicht fit für Ihre Zwecke (
DelayQueue
,PriorityBlockingQueue
undSynchronousQueue
).LinkedBlockingQueue
undLinkedBlockingDeque
sind identisch, außer dass letztere eine doppelendige Warteschlange ist (sie implementiert die Deque-Schnittstelle).Da dies
ArrayBlockingQueue
nur nützlich ist, wenn Sie die Anzahl der Elemente begrenzen möchten, würde ich mich daran haltenLinkedBlockingQueue
.quelle
ArrayBlockingQueue hat einen geringeren Speicherbedarf und kann Elementknoten wiederverwenden, ähnlich wie LinkedBlockingQueue, die für jede neue Einfügung ein LinkedBlockingQueue $ Node-Objekt erstellen müssen.
quelle
ArrayBlockingQueue
werden muss, hat sie einen viel schlechteren Speicherbedarf. Während der gesamten Zeit ist immer noch ein großes Array im Speicher zugeordnet DasLinkedBlockingQueue
wird einen vernachlässigbaren Speicherbedarf haben, wenn es fast leer ist.SynchronousQueue
(Aus einer anderen Frage entnommen )SynchronousQueue
ist eher eine Übergabe, während dasLinkedBlockingQueue
nur ein einzelnes Element erlaubt. Der Unterschied besteht darin, dass derput()
Anruf an aSynchronousQueue
erst bei einem entsprechendentake()
Anruf zurückgegeben wird. Bei einem AnrufLinkedBlockingQueue
der Größe 1 wird derput()
Anruf (an eine leere Warteschlange) jedoch sofort zurückgegeben. Dies ist im Wesentlichen dieBlockingQueue
Implementierung, wenn Sie nicht wirklich eine Warteschlange möchten (Sie möchten keine ausstehenden Daten verwalten).LinkedBlockingQueue
(LinkedList
Implementierung, aber nicht genau JDK-ImplementierungLinkedList
verwendet den statischen Knoten der inneren Klasse, um Verknüpfungen zwischen Elementen aufrechtzuerhalten.)Konstruktor für LinkedBlockingQueue
Knotenklasse Zum Verwalten von Links
3 . ArrayBlockingQueue (Array-Implementierung)
Konstruktor für ArrayBlockingQueue
IMHO Größter Unterschied zwischen
ArrayBlockingQueue
undLinkedBlockingQueue
ist klar aus Konstruktor, dem die zugrunde liegende Datenstruktur Array und andere linkedList zugrunde liegen .ArrayBlockingQueue
verwendet den Single-Lock-Double-Bedingungsalgorithmus undLinkedBlockingQueue
ist eine Variante des "Two-Lock-Queue" -Algorithmus. Er verfügt über 2 Locks und 2 Condition-Bedingungen (takeLock, putLock).quelle
ConcurrentLinkedQueue ist sperrenfrei, LinkedBlockingQueue nicht. Jedes Mal, wenn Sie LinkedBlockingQueue.put () oder LinkedBlockingQueue.take () aufrufen, müssen Sie zuerst die Sperre erwerben. Mit anderen Worten, LinkedBlockingQueue weist eine schlechte Parallelität auf. Wenn Sie Wert auf Leistung legen, versuchen Sie es mit ConcurrentLinkedQueue + LockSupport.
quelle