LinkedBlockingQueue wird auch mithilfe einer einseitig verknüpften Liste implementiert. Es verfügt außerdem über zwei Knoten, die zum Speichern des ersten bzw. letzten Knotens verwendet werden, und es gibt auch eine atomare Variablenanzahl mit einem Anfangswert von 0, die verwendet wird Notieren Sie die Anzahl der Warteschlangenelemente. Es gibt auch zwei Instanzen von ReentrantLock, mit denen die Atomizität der eintretenden bzw. aus der Warteschlange entfernten Elemente gesteuert wird. TakeLock wird verwendet, um zu steuern, dass nur ein Thread gleichzeitig Elemente aus dem Warteschlangenkopf abrufen kann und andere Threads dies tun müssen wait steuert, dass nur ein Thread gleichzeitig Elemente vom Warteschlangenkopf erhalten kann und Elemente zum Ende der Warteschlange hinzufügen kann. Darüber hinaus sind notEmpty und notFull Bedingungsvariablen. Sie verfügen über eine interne Bedingungswarteschlange zum Speichern von Threads, die beim Betreten und Verlassen der Warteschlange blockiert werden. Im Folgenden finden Sie den Code zum Erstellen einer exklusiven Sperre.
private final AtomicInteger count = new AtomicInteger(); /** Lock held by take, poll, etc */ private final ReentrantLock takeLock = new ReentrantLock(); /** Wait queue for waiting takes */ private final Condition notEmpty = takeLock.newCondition(); /** Lock held by put, offer, etc */ private final ReentrantLock putLock = new ReentrantLock(); /** Wait queue for waiting puts */ private final Condition notFull = putLock.newCondition();
Wenn der aufrufende Thread Vorgänge wie Take und Poll für die LinkedBlockingQueue-Instanz ausführt, muss er die takeLock-Sperre erhalten, um sicherzustellen, dass nur ein Thread gleichzeitig den Kopfknoten der verknüpften Liste bedienen kann. Da außerdem die Pflege der Bedingungswarteschlange innerhalb der Bedingungsvariablen notEmpty den Sperrstatusverwaltungsmechanismus von takeLock verwendet, muss der aufrufende Thread zunächst die takeLock-Sperre erhalten, bevor er die Warte- und Signalmethoden von notEmpty aufruft. Andernfalls wird eine IllegalMonitorStateException-Ausnahme ausgelöst . NotEmpty verwaltet intern eine Bedingungswarteschlange und ruft die Wartemethode von notEmpty auf. Anschließend wird der Thread in die Bedingungswarteschlange innerhalb von notEmpty gestellt, um zu warten, bis ein Thread das notEmpty-Signal aufruft Verfahren.
Wenn Sie Put-, Offer- und andere Vorgänge für die LinkedBlockingQueue-Instanz ausführen, müssen Sie die putLock-Sperre erhalten, um sicherzustellen, dass nur ein Thread gleichzeitig den Endknoten der verknüpften Liste bedienen kann. Da die Verwaltung der Bedingungswarteschlange innerhalb der Bedingungsvariablen notFull den Sperrstatusverwaltungsmechanismus von putLock verwendet, muss der aufrufende Thread zunächst die putLock-Sperre erwerben, bevor er die Warten- und Signalmethoden von notFull aufruft. Andernfalls wird eine IllegalMonitorStateException-Ausnahme ausgelöst. NotFull verwaltet intern eine Bedingungswarteschlange. Wenn ein Thread die putLock-Sperre erhält und die Wartemethode von notFull aufruft, wird der aufrufende Thread blockiert und dann in die Bedingungswarteschlange in notFull gestellt, um zu warten, bis ein Thread notFull aufruft. Signalmethode. Das Folgende ist der Code für den parameterlosen Konstruktor von LinkedBlockingQueue.
Das Folgende ist der Parameter-freie Konstruktionscode von LinkedBlockingQueue
public static final int MAX_VALUE = 0x7fffffff; public LinkedBlockingQueue() { this(Integer.MAX_VALUE); } public LinkedBlockingQueue(int capacity) { if (capacity <= 0) throw new IllegalAgrumentException(); this.capacity = capacity; last = head = new Node<E>(null); }
Aus diesem Code ist ersichtlich, dass die Standardwarteschlangenkapazität 0x7fffffff beträgt und Benutzer die Kapazität auch selbst angeben können, sodass dies bis zu einem gewissen Grad möglich ist sagte, dass LinkedBlockingQueue eine begrenzte Blockierungswarteschlange ist.
Offer-Operation
public boolean offer(E e) { //(1) if (e == null) throw new NullPointerException(); //(2) final AtomicInteger count = this.count; if (count.get() == capacity) return false; //(3) int c = -1; Node<E> node = new Node<E>(e); final ReentrantLock putLock = this.putLock; putLock.lock(); try { //(4) if (count.get() < capacity) { enqueue(node); c = count.getAndIncrement(); //(5) if (c + 1 < capacity) notFull.signal(); } } finally { //(6) putLock.unlock(); } //(7) if (c == 0) signalNotEmpty(); //(8) return c >= 0; }
Code (2) bestimmt, ob die aktuelle Warteschlange voll ist, verwirft das aktuelle Element und gibt false zurück.
Code (3) erhält die putLock-Sperre, nachdem der aktuelle Thread die Sperre erhalten hat put und Der Thread, der das Angebot ausführt, wird blockiert (der blockierte Thread wird in die AQS-Blockierungswarteschlange der putLock-Sperre gestellt).
Code (4) beurteilt hier erneut, ob die aktuelle Warteschlange voll ist. Dies liegt daran, dass andere Threads während der Ausführung von Code (2) und dem Erwerb der putLock-Sperre möglicherweise durch Put- oder Offer-Vorgänge neue Elemente zur Warteschlange hinzugefügt haben . Wenn die Warteschlange tatsächlich nicht voll ist, werden neue Elemente zur Warteschlange hinzugefügt und der Zähler wird erhöht.
Code (5) legt fest, dass, wenn nach dem Hinzufügen des neuen Elements zur Warteschlange noch freier Speicherplatz in der Warteschlange vorhanden ist, dasjenige in der bedingten Warteschlange, das notFull aufweckt, blockiert wird, weil die Warteoperation von notFull aufgerufen wird (z. B Wenn die Put-Methode ausgeführt wird und die Warteschlange voll ist) Thread: Da die Warteschlange jetzt inaktiv ist, kann ein Thread in der Warteschlange im Voraus aktiviert werden.
Code (6) gibt die erworbene putLock-Sperre frei. Hierbei ist zu beachten, dass die Freigabe der Sperre in „final“ erfolgen muss, da „final“ auch dann ausgeführt wird, wenn der try-Block eine Ausnahme auslöst. Nachdem die Sperre aufgehoben wurde, erhält außerdem einer der anderen Threads, die durch den Aufruf der Put-Operation blockiert wurden, die Sperre.
C0 in Code (7) zeigt an, dass sich mindestens ein Element in der Warteschlange befindet, wenn Code (6) zum Aufheben der Sperre ausgeführt wird. Wenn sich ein Element in der Warteschlange befindet, wird die Operation signalNotEmpty ausgeführt.
Das obige ist der detaillierte Inhalt vonWie verwende ich die LinkedBlockingQueue-Warteschlange in der gleichzeitigen Java-Programmierung?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!