1. Was ist eine blockierende Warteschlange?
Eine Warteschlange ist eine Datenstruktur, die zwei grundlegende Operationen hat: Hinzufügen eines Elements am Ende der Warteschlange und Entfernen eines Elements aus dem Kopf der Warteschlange. Der Unterschied zwischen Blockierungsteams und gewöhnlichen Warteschlangen besteht darin, dass gewöhnliche Warteschlangen den aktuellen Thread nicht blockieren. Bei ähnlichen Verbraucher-Produzenten-Modellen müssen zusätzliche Synchronisationsstrategien und Weckstrategien zwischen den Threads implementiert werden. Durch die Verwendung einer blockierenden Warteschlange blockiert der aktuelle Thread. Wenn die Warteschlange leer ist, wird der Betrieb, Elemente aus der Warteschlange zu erhalten, blockiert. Wenn die Warteschlange voll ist, wird auch der Betrieb des Hinzufügens von Elementen zur Warteschlange blockiert.
2. Die Hauptblockierungswarteschlange und ihre Methoden
Das Java.util.Concurrent -Paket bietet mehrere wichtigste Blockierungswarteschlangen, hauptsächlich wie folgt:
1) ArrayBlockingQueue: Eine blockierende Warteschlange basierend auf Array -Implementierung. Beim Erstellen eines ArrayBlockingqueue -Objekts muss seine Kapazität angegeben werden. Es kann auch für Zugriffsrichtlinien angegeben werden. Standardmäßig ist es nicht fair, das heißt, es garantiert nicht, dass der Thread mit der längsten Wartezeit zuerst auf die Warteschlange zugreifen kann.
2) Linked BlockingQueue: Eine blockierende Warteschlange basierend auf einer verknüpften Liste. Wenn die Kapazitätsgröße beim Erstellen eines LinkedBlocking -Objekts nicht angegeben ist, ist die Standardgröße ganzzahlig.max_Value.
3) Die beiden oben genannten Warteschlangen sind erstmals in den ersten ersten Warteschlangen, aber PriorityBlockingQueue nicht. Es wird die Elemente nach Priorität der Elemente und Dequeue in Prioritätsreihenfolge sortieren. Jedes Element Dequeue ist das Element mit höchster Priorität. Beachten Sie, dass diese blockierende Warteschlange eine unbegrenzte blockierende Warteschlange ist, dh es gibt keine Obergrenze für die Kapazität (Sie können durch den Quellcode wissen, dass es kein Signalflag mit dem Container hat). Die ersten beiden Typen sind begrenzte Warteschlangen.
4) Verzögerungsqueue: Basierend auf Prioritätsqueue, einer Verzögerungsblockierungswarteschlange. Das Element im Delayqueue kann das Element nur aus der Warteschlange erhalten, wenn die angegebene Verzögerungszeit erreicht ist. DelayQueue ist auch eine unbegrenzte Warteschlange, daher wird der Betrieb (Produzent), Daten in die Warteschlange einzufügen, niemals blockiert, und nur der Betrieb (Verbraucher), Daten zu erhalten, wird blockiert.
Die Blockierung von Warteschlangen umfasst die meisten Methoden in nicht blockierenden Warteschlangen und bieten mehrere andere sehr nützliche Methoden:
Die Put -Methode wird verwendet, um Elemente am Schwanz der Warteschlange zu speichern. Wenn die Warteschlange voll ist, warten Sie.
Die Take -Methode wird verwendet, um Elemente aus der Warteschlange zu erhalten, und wenn die Warteschlange leer ist, warten Sie.
Die Angebotsmethode wird verwendet, um Elemente am Schwanz der Warteschlange zu speichern. Wenn die Warteschlange voll ist, wartet sie auf eine bestimmte Zeit. Wenn der Zeitraum erreicht ist, wird die Einfügung nicht erfolgreich sein, wenn die Einfügung nicht erfolgreich war. Andernfalls wird es wahr zurückkehren;
Die Umfragemethode wird verwendet, um Elemente aus der ersten Warteschlange zu erhalten. Wenn die Warteschlange leer ist, wartet sie auf eine bestimmte Zeit. Wenn der Zeitraum erreicht ist, wird null zurückgegeben, wenn sie abgerufen wird. Andernfalls gibt es das erhaltene Element zurück;
Hier ist ein Code:
Importieren Sie Java.util.concurrent.ArrayBlockingQueue;/** * @Author Autor: Xu Jiane-Mail: [email protected] * @Version erstellt: 20. März 2016 um 12:52:53 PM * Klasse Beschreibung java.util.concurrent.BlockingQueue <String> blockingQueue = new ArrayBlockingQueue <> (5); für (int i = 0; i <10; i ++) {// Fügen Sie das angegebene Element dieser Warteschlange Blockingqueue.put ("Element hinzufügen"+i) hinzu; System.out.println ("Element zur blockierenden Warteschlange hinzugefügt:" + i); } System.out.println ("Das Programm endet dieses Mal und wird verlassen ----"); }}
Wenn die Anzahl der begrenzten Blockierungswarteschlangen 5 beträgt, wird nach dem Hinzufügen von 5 Elementen der Prozess außerhalb der Warteschlange und Wartezeit blockiert, und das Programm endet zu diesem Zeitpunkt nicht.
Wenn die Warteschlange voll ist, entfernen wir das Header -Element und können weiterhin Elemente zur blockierenden Warteschlange hinzufügen. Der Code ist wie folgt:
public class Blockingqueue {public static void main (String [] args) löst unterbrochene Ausnahme aus {java.util.concurrent für (int i = 0; i <10; i ++) {// Fügen Sie das angegebene Element dieser Warteschlange Blockingqueue.put ("Element hinzufügen"+i) hinzu; System.out.println ("Element zur blockierenden Warteschlange hinzugefügt:" + i); if (i> = 4) system.out.println ("das Header -Element entfernen" +blockingqueue.take ()); } System.out.println ("Das Programm endet dieses Mal und wird verlassen ----"); }Die Ausführungsergebnisse sind wie folgt:
3.. Implementierungsprinzip der Blockierung der Warteschlange <BR /> Im Folgenden befasst sich hauptsächlich das Implementierungsprinzip von ArrayBlockingQueue.
Schauen wir uns zunächst die Mitgliedervariablen der ArrayBlockingQueue -Klasse an:
public class ArrayBlockingQueue <E> erweitert AbstractQueue <E> implementiert Blockingqueue <E>, java.io.serializable { / ** zugrunde liegende Speicherstruktur-Array* / Final Object [] Elemente; / ** Team Head -Element -Index*/ int takeIdex; / ** Team Tail Element -Index*/ int PutIndex; / ** Gesamtzahl der Warteschlangenelemente*/ int Count; / ** Reentrantlock*/ Final Reentrantlock Lock; / ** NotizeTy Wait -Zustand*/ / ** Notvoller Wartezustand*/ privater endgültiger Zustand Notvoller; /** * Shared Status für aktuell aktive Iteratoren oder null, wenn es keine bekannten, keine zu geben. Ermöglicht die Warteschlangenoperationen zum Aktualisieren des * Iteratorstatus. */ transient iTRS iTRS = NULL;Wie Sie sehen können, ist der ArrayBlockingQueue, der zum Speichern von Elementen verwendet wird, tatsächlich ein Array.
Schauen wir uns die Implementierung von zwei wichtigen Methoden von ArrayBlockingqueue, Put () und Take () an:
public void put (e e) löst InterruptedException aus {// prüft zuerst, ob E leer ist, checknotnull (e); // Erwerben Sie das Lock Final Reentrantlock Lock = this.lock; lock.lockinterruptible (); Versuchen Sie es {// Wenn die Warteschlange voll ist, geben Sie den Zustand ein und warten Sie, während (count == items.length) Notful.await (); // Die Warteschlange ist nicht erfüllt, führen Sie den Warteschlangenbetrieb Enqueue (e) durch; } endlich {// veröffentlichen die lock lock.unlock (); }} Schauen wir uns den spezifischen Verbindungsvorgang an:
private void Enqueue (e x) {endgültiges Objekt [] items = this.items; // Entminationselemente [PutIndex] = x; if (++ putIndex == items.length) putIndex = 0; // Gesamtzahl der Warteschlangen +1 Graf ++; // einen Thread zufällig in der Warteschleife der notwendigen Bedingung auswählen, um seinen Blockierungszustand notieren zu entsperren. Signal (); } Hier ist der Quellcode der Methode take ():
public e take () wirft InterruptedException aus {// das Lock Final Reentrantlock lock = this.lock; lock.lockinterruptible (); Versuchen Sie {// Die Warteschlange ist leer, während (count == 0) // Der Thread verbindet sich mit dem Notizty -Bedingung, der WarteMpty.await (); // Nicht leer, beenden Sie die Warteschlange return dequeue (); } endlich {// veröffentlichen die lock lock.unlock (); }} 4. Anwendung der Blockierung von Warteschlangen: Implementierung des Verbraucher-Produzentenmodells
/** * @Author Autor: Xu Jiane-Mail: [email protected] * @Version erstellt Zeit: 20. März 2016 um 14:21:55 Uhr * Klasse Beschreibung: Verbraucher-Produzent-Modus, der durch Blockieren der Warteschlange */public class Test {private Int Queuesize = 10; private ArrayBlockingQueue <Ganzzahl> queue = new ArrayBlockingClockingQueue <Ganzzahl> (Queuesize); public static void main (String [] args) {Test test = new Test (); Produzent produzent = Test.New Producer (); Consumer Consumer = Test.New Consumer (); Produzent.Start (); Consumer.Start (); } class Consumer erweitert Thread {@Override public void run () {conssum (); } private void Consumption () {while (true) {try {queue.take (); System.out.println ("Nehmen Sie ein Element aus der Warteschlange, und die Warteschlange bleibt" + queue.size () + "Elemente"); } catch (interruptedException e) {e.printstacktrace (); }}}} Klasse -Produzent erweitert Thread {@Override public void run () {produc (); } private void produc () {while (true) {try {queue.put (1); System.out.println ("Ein Element in die Warteschlange einfügen, den verbleibenden Speicherplatz in der Warteschlange:"+ (Warteschlange - Queue.Size ())); } catch (interruptedException e) {e.printstacktrace (); }}}}}}
Das Obige dreht sich alles um diesen Artikel, ich hoffe, es wird für das Lernen aller hilfreich sein.