Blockingqueue og Dens Implementeringer
Grundlæggende BlockingQueue-implementeringer
Vi gennemgår ikke hver realisering i detaljer, da det ville tage meget tid, og det er usandsynligt, at du får brug for dem alle. Jeg vil tale om de generelle koncepter og hvilke konstruktører de har.
Eksempel fra virkeligheden
Forestil dig en fabrik, hvor én tråd, producenten, fremstiller dele, og en anden tråd, forbrugeren, behandler dem. Producenten placerer delene i en kø, mens forbrugeren henter og behandler dem fra køen. Hvis køen løber tør for dele, venter forbrugeren på, at producenten tilføjer flere. Omvendt, hvis køen er fuld, venter producenten på, at forbrugeren skaber plads.
Lidt længere nede vil vi implementere denne opgave i kode.
Forskelle fra andre samlingstyper
BlockingQueue tilbyder automatisk synkronisering, som håndterer trådadgang til køen uden behov for manuel synkronisering. Den understøtter også blokerende operationer til tilføjelse og hentning af elementer, en funktion der ikke findes i andre samlinger som ArrayList eller LinkedList.
BlockingQueue-implementeringer
ArrayBlockingQueue: En størrelsesbegrænset kø, der bruger et array til at gemme elementer.
Main.java
123456789// Constructor with fixed capacity BlockingQueue<String> queue1 = new ArrayBlockingQueue<>(5); // Constructor with fixed capacity and fair access BlockingQueue<String> queue2 = new ArrayBlockingQueue<>(5, true); // Constructor with fixed capacity and initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new ArrayBlockingQueue<>(5, false, initialElements);
true-parameteren muliggør en retfærdig adgangspolitik ved at sikre FIFO-rækkefølge for trådadgang.
LinkedBlockingQueueue: En kø baseret på sammenkædede noder, som kan være begrænset eller ubegrænset.
Main.java
123456789// Constructor without capacity bounds BlockingQueue<String> queue1 = new LinkedBlockingQueue<>(); // Constructor with fixed capacity BlockingQueue<String> queue2 = new LinkedBlockingQueue<>(5); // Constructor with initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new LinkedBlockingQueue<>(initialElements);
PriorityBlockingQueue: En ubegrænset prioriteret kø, hvor elementer hentes i henhold til deres naturlige rækkefølge eller som angivet af en comparator.
Main.java
12345678910111213// Constructor without initial capacity (default is 11) BlockingQueue<Integer> queue1 = new PriorityBlockingQueue<>(); // Constructor with initial capacity BlockingQueue<Integer> queue2 = new PriorityBlockingQueue<>(5); // Constructor with initial capacity and comparator Comparator<Integer> comparator = Integer::compareTo; BlockingQueue<Integer> queue3 = new PriorityBlockingQueue<>(5, comparator); // Constructor with initial collection of elements Collection<Integer> initialElements = java.util.Arrays.asList(1, 3, 2); BlockingQueue<Integer> queue4 = new PriorityBlockingQueue<>(initialElements)
DelayQueue: En forsinket kø, hvor elementer kun kan hentes efter, at deres forsinkelse er udløbet.
DelayedElement.java
DelayQueueConstructors.java
123456789101112131415161718class DelayedElement implements Delayed { private final long expirationTime; // The time when the element will be available public DelayedElement(long delay, TimeUnit unit) { this.expirationTime = System.currentTimeMillis() + unit.toMillis(delay); } @Override public long getDelay(TimeUnit unit) { long delay = expirationTime - System.currentTimeMillis(); // Calculate the remaining delay return unit.convert(delay, TimeUnit.MILLISECONDS); // Convert the delay to the specified time unit } @Override public int compareTo(Delayed o) { return Long.compare(this.expirationTime, ((DelayedElement) o).expirationTime); } }
Denne kode illustrerer brugen af klassen DelayedElement, som implementerer interfacet Delayed, samt forsinkelseskøen DelayQueue i Java. Klassen DelayedElement definerer en metode getDelay til at beregne den resterende forsinkelsestid og en metode compareTo til at sammenligne objekter baseret på udløbstidspunktet for forsinkelsen.
Metoden main opretter to køer: queue1, en tom forsinkelseskø, og queue2, en kø initialiseret med elementer, der har en forsinkelse på henholdsvis 5 og 1 sekund.
Elementerne i DelayQueueue bliver tilgængelige for hentning, når den angivne forsinkelsestid er udløbet.
SynchronousQueueue: En kø uden kapacitet, hvor hver indsættelsesoperation skal vente på den tilsvarende udtræksoperation og omvendt.
Main.java
12345// Constructor without fair access BlockingQueue<String> queue1 = new SynchronousQueue<>(); // Constructor with fair access BlockingQueue<String> queue2 = new SynchronousQueue<>(true);
De vigtigste metoder i BlockingQueue:
Tilføjelse af elementer:
Metoden void put(E e) indsætter et element i køen og blokerer tråden, hvis køen er fuld. Alternativt forsøger metoden boolean offer(E e, long timeout, TimeUnit unit) at tilføje et element til køen og venter i den angivne tid, hvis køen er fuld.
Main.java
1234567891011121314151617public class BlockingQueueExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { queue.put("Element 1"); // Insert the first element, no blocking. queue.put("Element 2"); // Insert the second element, no blocking. // Try to add the third element with a 2-second timeout. // Since the queue is full, it will wait for 2 seconds. boolean success = queue.offer("Element 3", 2, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } }
Dette eksempel demonstrerer indsættelse af to elementer i en BlockingQueue uden blokering, efterfulgt af et forsøg på at tilføje et tredje element med en 2-sekunders timeout ved brug af offer()-metoden, som vil vente, hvis køen er fuld.
Elementhentning:
Metoden E take() henter og returnerer et element fra køen og blokerer tråden, hvis køen er tom. Alternativt forsøger metoden E poll(long timeout, TimeUnit unit) at hente et element fra køen og venter i den angivne tid, hvis køen er tom.
Main.java
1234567891011121314151617181920212223public class BlockingQueueRetrievalExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Retrieve and remove the first element, no blocking since the queue is not empty String item1 = queue.take(); // Returns "Element 1" // Attempt to retrieve and remove the next element with a 2-second timeout String item2 = queue.poll(2, TimeUnit.SECONDS); // Returns "Element 2" // Attempt to retrieve an element when the queue is empty, this will block for 2 seconds String item3 = queue.poll(2, TimeUnit.SECONDS); // Returns `null` after timeout } catch (InterruptedException e) { e.printStackTrace(); } } }
Denne kode tilføjer to elementer til en BlockingQueue, henter og fjerner det første element med det samme, forsøger at hente det næste element med en 2-sekunders timeout, og prøver til sidst at hente et element fra en tom kø, hvilket resulterer i null efter timeouten.
Kontrol og fjernelse af elementer:
Metoden boolean remove(Object o) fjerner det angivne element fra køen, hvis det er til stede. Omvendt kontrollerer metoden boolean contains(Object o), om det angivne element er til stede i køen uden at fjerne det.
Main.java
1234567891011121314151617181920212223242526public class BlockingQueueCheckRemoveExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Check if "Element 1" is in the queue, should return `true` boolean containsElement1 = queue.contains("Element 1"); // true // Remove "Element 1" from the queue, should return `true` boolean removedElement1 = queue.remove("Element 1"); // true // Check if "Element 1" is still in the queue, should return `false` boolean containsElement1AfterRemoval = queue.contains("Element 1"); // false // Try to remove an element that is not in the queue, should return `false` boolean removedElement3 = queue.remove("Element 3"); // false } catch (InterruptedException e) { e.printStackTrace(); } } }
Denne kode tilføjer to elementer til en BlockingQueue, kontrollerer tilstedeværelsen af "Element 1", fjerner det, kontrollerer igen for at bekræfte dets fjernelse, og forsøger derefter at fjerne et ikke-eksisterende element.
Forespørgsler på køens tilstand:
Metoden int size() returnerer antallet af elementer der aktuelt er i køen. For at afgøre om køen er tom, kan du bruge metoden boolean isEmpty(), som kontrollerer om køen ikke indeholder nogen elementer. For køer med fast kapacitet giver metoden int remainingCapacity() antallet af resterende tilgængelige pladser i køen.
Main.java
123456789101112131415161718192021222324252627282930public class BlockingQueueCapacityExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Get the number of elements in the queue int currentSize = queue.size(); // 2 // Check if the queue is empty boolean isQueueEmpty = queue.isEmpty(); // false // Get the remaining capacity in the queue int remainingSpace = queue.remainingCapacity(); // 1 // Add another element to fill the queue queue.put("Element 3"); // Check the size and remaining capacity after adding the third element currentSize = queue.size(); // 3 remainingSpace = queue.remainingCapacity(); // 0 } catch (InterruptedException e) { e.printStackTrace(); } } }
Denne kode tilføjer elementer til en BlockingQueue, kontrollerer aktuel størrelse, verificerer om køen er tom, og bestemmer den resterende kapacitet, hvorefter disse værdier opdateres efter at køen er fyldt helt op.
Realisering af et virkelighedsnært eksempel i kode
😭 Begrænsninger
En væsentlig begrænsning er ydelse: på grund af de låseoperationer, der er involveret, kan ydelsen være reduceret sammenlignet med ikke-synkroniserede samlinger. Derudover kan ressourcer blive et problem, da store køer kræver mere hukommelse og CPU-tid for at håndtere låse og synkroniseringsprocesser.
💪 Fordele
På den positive side er systemet sikkert i multitrådsmiljøer, hvilket giver sikker kommunikation mellem tråde uden behov for manuel synkroniseringsstyring. Det forenkler også koden ved at undgå komplekse synkroniserings- og blokeringskonstruktioner. Desuden betyder fleksibiliteten i forskellige BlockingQueue-implementeringer, at de kan tilpasses forskellige anvendelsesscenarier.
1. Hvad er en BlockingQueue i Java?
2. Hvad er de vigtigste metoder i BlockingQueue, der blokerer en tråd?
3. Hvad er BlockingQueue nyttig til i multitrådede applikationer?
Tak for dine kommentarer!
Spørg AI
Spørg AI
Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat
What are the main differences between the BlockingQueue implementations?
Can you explain how the DelayQueue works in more detail?
How does the producer-consumer example work in code?
Awesome!
Completion rate improved to 3.33
Blockingqueue og Dens Implementeringer
Stryg for at vise menuen
Grundlæggende BlockingQueue-implementeringer
Vi gennemgår ikke hver realisering i detaljer, da det ville tage meget tid, og det er usandsynligt, at du får brug for dem alle. Jeg vil tale om de generelle koncepter og hvilke konstruktører de har.
Eksempel fra virkeligheden
Forestil dig en fabrik, hvor én tråd, producenten, fremstiller dele, og en anden tråd, forbrugeren, behandler dem. Producenten placerer delene i en kø, mens forbrugeren henter og behandler dem fra køen. Hvis køen løber tør for dele, venter forbrugeren på, at producenten tilføjer flere. Omvendt, hvis køen er fuld, venter producenten på, at forbrugeren skaber plads.
Lidt længere nede vil vi implementere denne opgave i kode.
Forskelle fra andre samlingstyper
BlockingQueue tilbyder automatisk synkronisering, som håndterer trådadgang til køen uden behov for manuel synkronisering. Den understøtter også blokerende operationer til tilføjelse og hentning af elementer, en funktion der ikke findes i andre samlinger som ArrayList eller LinkedList.
BlockingQueue-implementeringer
ArrayBlockingQueue: En størrelsesbegrænset kø, der bruger et array til at gemme elementer.
Main.java
123456789// Constructor with fixed capacity BlockingQueue<String> queue1 = new ArrayBlockingQueue<>(5); // Constructor with fixed capacity and fair access BlockingQueue<String> queue2 = new ArrayBlockingQueue<>(5, true); // Constructor with fixed capacity and initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new ArrayBlockingQueue<>(5, false, initialElements);
true-parameteren muliggør en retfærdig adgangspolitik ved at sikre FIFO-rækkefølge for trådadgang.
LinkedBlockingQueueue: En kø baseret på sammenkædede noder, som kan være begrænset eller ubegrænset.
Main.java
123456789// Constructor without capacity bounds BlockingQueue<String> queue1 = new LinkedBlockingQueue<>(); // Constructor with fixed capacity BlockingQueue<String> queue2 = new LinkedBlockingQueue<>(5); // Constructor with initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new LinkedBlockingQueue<>(initialElements);
PriorityBlockingQueue: En ubegrænset prioriteret kø, hvor elementer hentes i henhold til deres naturlige rækkefølge eller som angivet af en comparator.
Main.java
12345678910111213// Constructor without initial capacity (default is 11) BlockingQueue<Integer> queue1 = new PriorityBlockingQueue<>(); // Constructor with initial capacity BlockingQueue<Integer> queue2 = new PriorityBlockingQueue<>(5); // Constructor with initial capacity and comparator Comparator<Integer> comparator = Integer::compareTo; BlockingQueue<Integer> queue3 = new PriorityBlockingQueue<>(5, comparator); // Constructor with initial collection of elements Collection<Integer> initialElements = java.util.Arrays.asList(1, 3, 2); BlockingQueue<Integer> queue4 = new PriorityBlockingQueue<>(initialElements)
DelayQueue: En forsinket kø, hvor elementer kun kan hentes efter, at deres forsinkelse er udløbet.
DelayedElement.java
DelayQueueConstructors.java
123456789101112131415161718class DelayedElement implements Delayed { private final long expirationTime; // The time when the element will be available public DelayedElement(long delay, TimeUnit unit) { this.expirationTime = System.currentTimeMillis() + unit.toMillis(delay); } @Override public long getDelay(TimeUnit unit) { long delay = expirationTime - System.currentTimeMillis(); // Calculate the remaining delay return unit.convert(delay, TimeUnit.MILLISECONDS); // Convert the delay to the specified time unit } @Override public int compareTo(Delayed o) { return Long.compare(this.expirationTime, ((DelayedElement) o).expirationTime); } }
Denne kode illustrerer brugen af klassen DelayedElement, som implementerer interfacet Delayed, samt forsinkelseskøen DelayQueue i Java. Klassen DelayedElement definerer en metode getDelay til at beregne den resterende forsinkelsestid og en metode compareTo til at sammenligne objekter baseret på udløbstidspunktet for forsinkelsen.
Metoden main opretter to køer: queue1, en tom forsinkelseskø, og queue2, en kø initialiseret med elementer, der har en forsinkelse på henholdsvis 5 og 1 sekund.
Elementerne i DelayQueueue bliver tilgængelige for hentning, når den angivne forsinkelsestid er udløbet.
SynchronousQueueue: En kø uden kapacitet, hvor hver indsættelsesoperation skal vente på den tilsvarende udtræksoperation og omvendt.
Main.java
12345// Constructor without fair access BlockingQueue<String> queue1 = new SynchronousQueue<>(); // Constructor with fair access BlockingQueue<String> queue2 = new SynchronousQueue<>(true);
De vigtigste metoder i BlockingQueue:
Tilføjelse af elementer:
Metoden void put(E e) indsætter et element i køen og blokerer tråden, hvis køen er fuld. Alternativt forsøger metoden boolean offer(E e, long timeout, TimeUnit unit) at tilføje et element til køen og venter i den angivne tid, hvis køen er fuld.
Main.java
1234567891011121314151617public class BlockingQueueExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { queue.put("Element 1"); // Insert the first element, no blocking. queue.put("Element 2"); // Insert the second element, no blocking. // Try to add the third element with a 2-second timeout. // Since the queue is full, it will wait for 2 seconds. boolean success = queue.offer("Element 3", 2, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } }
Dette eksempel demonstrerer indsættelse af to elementer i en BlockingQueue uden blokering, efterfulgt af et forsøg på at tilføje et tredje element med en 2-sekunders timeout ved brug af offer()-metoden, som vil vente, hvis køen er fuld.
Elementhentning:
Metoden E take() henter og returnerer et element fra køen og blokerer tråden, hvis køen er tom. Alternativt forsøger metoden E poll(long timeout, TimeUnit unit) at hente et element fra køen og venter i den angivne tid, hvis køen er tom.
Main.java
1234567891011121314151617181920212223public class BlockingQueueRetrievalExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Retrieve and remove the first element, no blocking since the queue is not empty String item1 = queue.take(); // Returns "Element 1" // Attempt to retrieve and remove the next element with a 2-second timeout String item2 = queue.poll(2, TimeUnit.SECONDS); // Returns "Element 2" // Attempt to retrieve an element when the queue is empty, this will block for 2 seconds String item3 = queue.poll(2, TimeUnit.SECONDS); // Returns `null` after timeout } catch (InterruptedException e) { e.printStackTrace(); } } }
Denne kode tilføjer to elementer til en BlockingQueue, henter og fjerner det første element med det samme, forsøger at hente det næste element med en 2-sekunders timeout, og prøver til sidst at hente et element fra en tom kø, hvilket resulterer i null efter timeouten.
Kontrol og fjernelse af elementer:
Metoden boolean remove(Object o) fjerner det angivne element fra køen, hvis det er til stede. Omvendt kontrollerer metoden boolean contains(Object o), om det angivne element er til stede i køen uden at fjerne det.
Main.java
1234567891011121314151617181920212223242526public class BlockingQueueCheckRemoveExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Check if "Element 1" is in the queue, should return `true` boolean containsElement1 = queue.contains("Element 1"); // true // Remove "Element 1" from the queue, should return `true` boolean removedElement1 = queue.remove("Element 1"); // true // Check if "Element 1" is still in the queue, should return `false` boolean containsElement1AfterRemoval = queue.contains("Element 1"); // false // Try to remove an element that is not in the queue, should return `false` boolean removedElement3 = queue.remove("Element 3"); // false } catch (InterruptedException e) { e.printStackTrace(); } } }
Denne kode tilføjer to elementer til en BlockingQueue, kontrollerer tilstedeværelsen af "Element 1", fjerner det, kontrollerer igen for at bekræfte dets fjernelse, og forsøger derefter at fjerne et ikke-eksisterende element.
Forespørgsler på køens tilstand:
Metoden int size() returnerer antallet af elementer der aktuelt er i køen. For at afgøre om køen er tom, kan du bruge metoden boolean isEmpty(), som kontrollerer om køen ikke indeholder nogen elementer. For køer med fast kapacitet giver metoden int remainingCapacity() antallet af resterende tilgængelige pladser i køen.
Main.java
123456789101112131415161718192021222324252627282930public class BlockingQueueCapacityExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Get the number of elements in the queue int currentSize = queue.size(); // 2 // Check if the queue is empty boolean isQueueEmpty = queue.isEmpty(); // false // Get the remaining capacity in the queue int remainingSpace = queue.remainingCapacity(); // 1 // Add another element to fill the queue queue.put("Element 3"); // Check the size and remaining capacity after adding the third element currentSize = queue.size(); // 3 remainingSpace = queue.remainingCapacity(); // 0 } catch (InterruptedException e) { e.printStackTrace(); } } }
Denne kode tilføjer elementer til en BlockingQueue, kontrollerer aktuel størrelse, verificerer om køen er tom, og bestemmer den resterende kapacitet, hvorefter disse værdier opdateres efter at køen er fyldt helt op.
Realisering af et virkelighedsnært eksempel i kode
😭 Begrænsninger
En væsentlig begrænsning er ydelse: på grund af de låseoperationer, der er involveret, kan ydelsen være reduceret sammenlignet med ikke-synkroniserede samlinger. Derudover kan ressourcer blive et problem, da store køer kræver mere hukommelse og CPU-tid for at håndtere låse og synkroniseringsprocesser.
💪 Fordele
På den positive side er systemet sikkert i multitrådsmiljøer, hvilket giver sikker kommunikation mellem tråde uden behov for manuel synkroniseringsstyring. Det forenkler også koden ved at undgå komplekse synkroniserings- og blokeringskonstruktioner. Desuden betyder fleksibiliteten i forskellige BlockingQueue-implementeringer, at de kan tilpasses forskellige anvendelsesscenarier.
1. Hvad er en BlockingQueue i Java?
2. Hvad er de vigtigste metoder i BlockingQueue, der blokerer en tråd?
3. Hvad er BlockingQueue nyttig til i multitrådede applikationer?
Tak for dine kommentarer!