Gids voor PriorityBlockingQueue in Java

1. Inleiding

In dit artikel zullen we ons concentreren op de PriorityBlockingQueue klas en bespreek enkele praktische voorbeelden.

Te beginnen met de aanname dat we al weten wat a Wachtrij is, zullen we eerst demonstreren hoe elementen in de PriorityBlockingQueue zijn gerangschikt op prioriteit.

Hierna zullen we demonstreren hoe dit type wachtrij kan worden gebruikt om een ​​thread te blokkeren.

Ten slotte laten we zien hoe het samen gebruiken van deze twee functies nuttig kan zijn bij het verwerken van gegevens over meerdere threads.

2. Prioriteit van elementen

In tegenstelling tot een standaardwachtrij, kunt u niet zomaar elk type element aan een PriorityBlockingQueue. Er zijn twee mogelijkheden:

  1. Elementen toevoegen die implementeren Vergelijkbaar
  2. Elementen toevoegen die niet worden geïmplementeerd Vergelijkbaar, op voorwaarde dat u een Comparator ook

Door ofwel de Comparator of de Vergelijkbaar implementaties om elementen te vergelijken, de PriorityBlockingQueue wordt altijd gesorteerd.

Het doel is om vergelijkingslogica te implementeren op een manier waarop het element met de hoogste prioriteit wordt altijd als eerste geordend. Als we vervolgens een element uit onze wachtrij verwijderen, is dit altijd het element met de hoogste prioriteit.

Laten we om te beginnen onze wachtrij in één thread gebruiken, in plaats van deze in meerdere te gebruiken. Door dit te doen, wordt het gemakkelijk om te bewijzen hoe elementen zijn geordend in een unit-test:

PriorityBlockingQueue wachtrij = nieuwe PriorityBlockingQueue (); ArrayList polledElements = nieuwe ArrayList (); queue.add (1); queue.add (5); wachtrij.add (2); queue.add (3); queue.add (4); queue.drainTo (polledElements); assertThat (polledElements) .containsExactly (1, 2, 3, 4, 5);

Zoals we kunnen zien, worden de elementen, ondanks het feit dat ze in een willekeurige volgorde aan de wachtrij zijn toegevoegd, geordend wanneer we ze beginnen te ondervragen. Dit komt doordat de Geheel getal klasse implementeert Vergelijkbaar, die op hun beurt worden gebruikt om ervoor te zorgen dat we ze in oplopende volgorde uit de wachtrij halen.

Het is ook de moeite waard om dat op te merken wanneer twee elementen worden vergeleken en hetzelfde zijn, is er geen garantie hoe ze worden besteld.

3. Gebruik de Wachtrij blokkeren

Als we te maken hadden met een standaard wachtrij, zouden we bellen poll () om elementen op te halen. Als de wachtrij echter leeg was, kunt u bellen naar poll () zou terugbrengen nul.

De PriorityBlockingQueue implementeert het BlockingQueue interface, wat ons een aantal extra methoden geeft waarmee we dat kunnen blok bij het verwijderen uit een lege wachtrij. Laten we proberen de nemen() methode, die precies dat zou moeten doen:

PriorityBlockingQueue wachtrij = nieuwe PriorityBlockingQueue (); new Thread (() -> {System.out.println ("Polling ..."); probeer {Integer poll = queue.take (); System.out.println ("Polled:" + poll);} catch ( InterruptedException e) {e.printStackTrace ();}}). Start (); Thread.sleep (TimeUnit.SECONDS.toMillis (5)); System.out.println ("Toevoegen aan wachtrij"); queue.add (1);

Hoewel het gebruik van slaap() is een ietwat broze manier om dingen te demonstreren, wanneer we deze code uitvoeren, zullen we zien:

Polling ... Toevoegen aan wachtrij Polled: 1 

Dit bewijst dat nemen() geblokkeerd totdat een item is toegevoegd:

  1. De thread zal "Polling" afdrukken om te bewijzen dat het is gestart
  2. De test zal dan ongeveer vijf seconden pauzeren om te bewijzen dat de thread moet hebben aangeroepen nemen() op dit punt
  3. We vullen de wachtrij aan en zouden min of meer onmiddellijk "Polled: 1" moeten zien om dat te bewijzen nemen() heeft een element geretourneerd zodra het beschikbaar kwam

Het is ook vermeldenswaard dat de BlockingQueue interface biedt ons ook manieren om te blokkeren bij het toevoegen aan volledige wachtrijen.

Een PriorityBlockingQueue is grenzeloos. Dit betekent dat het nooit vol zal zijn, dus het is altijd mogelijk om nieuwe elementen toe te voegen.

4. Blokkering en prioriteitstelling samen gebruiken

Nu we de twee belangrijkste concepten van a hebben uitgelegd Prioriteit Blokkeren Wachtrij, laten we ze allebei samen gebruiken. We kunnen eenvoudig ons vorige voorbeeld uitbreiden, maar deze keer voegen we meer elementen toe aan de wachtrij:

Thread thread = nieuwe Thread (() -> {System.out.println ("Polling ..."); while (true) {probeer {Integer poll = queue.take (); System.out.println ("Polling: "+ poll);} catch (InterruptedException e) {e.printStackTrace ();}}}); thread.start (); Thread.sleep (TimeUnit.SECONDS.toMillis (5)); System.out.println ("Toevoegen aan wachtrij"); queue.addAll (newArrayList (1, 5, 6, 1, 2, 6, 7)); Thread.sleep (TimeUnit.SECONDS.toMillis (1));

Nogmaals, hoewel dit een beetje broos is vanwege het gebruik van slaap(), het laat ons nog steeds een geldige use case zien. We hebben nu een wachtrij die blokkeert, wachtend op het toevoegen van elementen. We voegen dan veel elementen tegelijk toe en laten vervolgens zien dat ze in volgorde van prioriteit worden afgehandeld. De uitvoer ziet er als volgt uit:

Polling ... Toevoegen aan wachtrij Hoornloos: 1 Hoornloos: 1 Hoornloos: 2 Hoornloos: 5 Hoornloos: 6 Hoornloos: 6 Hoornloos: 7

5. Conclusie

In deze handleiding hebben we laten zien hoe we een PriorityBlockingQueue om een ​​thread te blokkeren totdat er enkele items aan zijn toegevoegd, en ook dat we die items kunnen verwerken op basis van hun prioriteit.

De implementatie van deze voorbeelden is te vinden op GitHub. Dit is een op Maven gebaseerd project, dus het zou gemakkelijk moeten zijn zoals het is.