Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Blockingqueue og Dens Implementasjoner | Synkroniserte Samlinger
Multitråding i Java

bookBlockingqueue og Dens Implementasjoner

Grunnleggende BlockingQueue-implementasjoner

Vi vil ikke gå gjennom hver implementasjon i detalj, da det ville tatt mye tid, og det er lite sannsynlig at du vil trenge dem alle. Jeg vil forklare de generelle konseptene og hvilke konstruktører de har.

Eksempel fra virkeligheten

Tenk deg en fabrikk der én tråd, produsenten, lager deler, og en annen tråd, konsumenten, bearbeider dem. Produsenten legger delene i en , mens konsumenten henter og bearbeider dem fra køen. Hvis køen går tom for deler, venter konsumenten på at produsenten skal legge til flere. Omvendt, hvis køen er full, venter produsenten på at konsumenten skal frigjøre plass.

Note
Merk

Litt lenger ned vil vi implementere denne oppgaven i kode.

Forskjeller fra andre samlingstyper

BlockingQueue gir automatisk synkronisering, og håndterer trådadgang til køen uten behov for manuell synkronisering. Den støtter også blokkerende operasjoner for å legge til og hente elementer, en funksjon som ikke finnes i andre samlinger som ArrayList eller LinkedList.

BlockingQueue-implementasjoner

ArrayBlockingQueue: En størrelsesbegrenset kø som bruker et array for å lagre elementer.

Main.java

Main.java

copy
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);
Note
Merk

true-parameteren aktiverer en rettferdig tilgangspolicy ved å gi en FIFO-rekkefølge for trådadgang.

LinkedBlockingQueueue: En kø basert på lenkede noder som kan være begrenset eller ubegrenset.

Main.java

Main.java

copy
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 ubegrenset prioritert kø der elementer hentes ut i henhold til deres naturlige rekkefølge eller som spesifisert av en komparator.

Main.java

Main.java

copy
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 etter at deres forsinkelse har utløpt.

DelayedElement.java

DelayedElement.java

DelayQueueConstructors.java

DelayQueueConstructors.java

copy
123456789101112131415161718
class 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 koden demonstrerer bruken av DelayedElement-klassen, som implementerer Delayed-interface, og forsinket kø (DelayQueue) i Java. DelayedElement-klassen definerer en getDelay-metode for å beregne gjenværende forsinkelsestid og en compareTo-metode for å sammenligne objekter basert på utløpstid for forsinkelse.

main-metoden oppretter to køer: queue1, en tom forsinket kø, og queue2, en kø initialisert med elementer som har en forsinkelse på 5 og 1 sekund, henholdsvis.

Elementene i DelayQueueue blir tilgjengelige for henting etter at den angitte forsinkelsestiden har utløpt.

SynchronousQueueue: En kø uten kapasitet, der hver innsettingsoperasjon må vente på den tilsvarende uttaksoperasjonen og omvendt.

Main.java

Main.java

copy
12345
// Constructor without fair access BlockingQueue<String> queue1 = new SynchronousQueue<>(); // Constructor with fair access BlockingQueue<String> queue2 = new SynchronousQueue<>(true);

Hovedmetodene til BlockingQueue:

Legge til elementer:

Metoden void put(E e) setter inn et element i køen, og blokkerer tråden hvis køen er full. Alternativt forsøker metoden boolean offer(E e, long timeout, TimeUnit unit) å legge til et element i køen, og venter i angitt tid hvis køen er full.

Main.java

Main.java

copy
1234567891011121314151617
public 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 eksemplet viser innsetting av to elementer i en BlockingQueue uten blokkering, etterfulgt av et forsøk på å legge til et tredje element med en 2-sekunders tidsavbrudd ved bruk av offer()-metoden, som vil vente dersom køen er full.

Henting av element:

Metoden E take() henter og returnerer et element fra køen, og blokkerer tråden dersom køen er tom. Alternativt forsøker metoden E poll(long timeout, TimeUnit unit) å hente et element fra køen, og venter i angitt tid dersom køen er tom.

Main.java

Main.java

copy
1234567891011121314151617181920212223
public 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 koden legger til to elementer i en BlockingQueue, henter ut og fjerner det første elementet umiddelbart, forsøker å hente ut neste element med en 2-sekunders tidsavbrudd, og prøver til slutt å hente ut et element fra en tom kø, noe som resulterer i null etter tidsavbruddet.

Kontrollere og fjerne elementer:

Metoden boolean remove(Object o) fjerner det spesifiserte elementet fra køen dersom det er til stede. På den annen side kontrollerer metoden boolean contains(Object o) om det spesifiserte elementet finnes i køen uten å fjerne det.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526
public 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 koden legger til to elementer i en BlockingQueue, sjekker om "Element 1" er til stede, fjerner det, sjekker igjen for å bekrefte at det er fjernet, og forsøker deretter å fjerne et ikke-eksisterende element.

Spørring om køens tilstand:

Metoden int size() returnerer antall elementer som for øyeblikket er i køen. For å avgjøre om køen er tom, kan du bruke metoden boolean isEmpty(), som sjekker om køen ikke inneholder noen elementer. For køer med fast kapasitet gir metoden int remainingCapacity() antall gjenværende ledige plasser i køen.

Main.java

Main.java

copy
123456789101112131415161718192021222324252627282930
public 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 koden legger til elementer i en BlockingQueue, sjekker nåværende størrelse, verifiserer om køen er tom, og fastslår gjenværende kapasitet, deretter oppdateres disse verdiene etter at køen er fylt helt opp.

Realisere et virkelighetsnært eksempel i kode

😭 Begrensninger

En sentral begrensning er ytelse: på grunn av låseoperasjoner kan ytelsen reduseres sammenlignet med ikke-synkroniserte samlinger. I tillegg kan ressurser bli et problem ettersom store køer krever mer minne og prosessor-tid for å håndtere låser og synkroniseringsprosesser.

💪 Fordeler

På den positive siden er systemet trygt i flertrådsmiljø, og gir sikker kommunikasjon mellom tråder uten behov for manuell synkroniseringshåndtering. Det forenkler også koden ved å unngå komplekse synkroniserings- og blokkeringskonstruksjoner. Videre gir fleksibiliteten til ulike BlockingQueue-implementasjoner mulighet for tilpasning til ulike bruksscenarier.

1. Hva er en BlockingQueue i Java?

2. Hva er hovedmetodene i BlockingQueue som blokkerer en tråd?

3. Hva er BlockingQueue nyttig for i flertrådede applikasjoner?

question mark

Hva er en BlockingQueue i Java?

Select the correct answer

question mark

Hva er hovedmetodene i BlockingQueue som blokkerer en tråd?

Select the correct answer

question mark

Hva er BlockingQueue nyttig for i flertrådede applikasjoner?

Select the correct answer

Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 2. Kapittel 3

Spør AI

expand

Spør AI

ChatGPT

Spør om hva du vil, eller prøv ett av de foreslåtte spørsmålene for å starte chatten vår

Awesome!

Completion rate improved to 3.33

bookBlockingqueue og Dens Implementasjoner

Sveip for å vise menyen

Grunnleggende BlockingQueue-implementasjoner

Vi vil ikke gå gjennom hver implementasjon i detalj, da det ville tatt mye tid, og det er lite sannsynlig at du vil trenge dem alle. Jeg vil forklare de generelle konseptene og hvilke konstruktører de har.

Eksempel fra virkeligheten

Tenk deg en fabrikk der én tråd, produsenten, lager deler, og en annen tråd, konsumenten, bearbeider dem. Produsenten legger delene i en , mens konsumenten henter og bearbeider dem fra køen. Hvis køen går tom for deler, venter konsumenten på at produsenten skal legge til flere. Omvendt, hvis køen er full, venter produsenten på at konsumenten skal frigjøre plass.

Note
Merk

Litt lenger ned vil vi implementere denne oppgaven i kode.

Forskjeller fra andre samlingstyper

BlockingQueue gir automatisk synkronisering, og håndterer trådadgang til køen uten behov for manuell synkronisering. Den støtter også blokkerende operasjoner for å legge til og hente elementer, en funksjon som ikke finnes i andre samlinger som ArrayList eller LinkedList.

BlockingQueue-implementasjoner

ArrayBlockingQueue: En størrelsesbegrenset kø som bruker et array for å lagre elementer.

Main.java

Main.java

copy
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);
Note
Merk

true-parameteren aktiverer en rettferdig tilgangspolicy ved å gi en FIFO-rekkefølge for trådadgang.

LinkedBlockingQueueue: En kø basert på lenkede noder som kan være begrenset eller ubegrenset.

Main.java

Main.java

copy
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 ubegrenset prioritert kø der elementer hentes ut i henhold til deres naturlige rekkefølge eller som spesifisert av en komparator.

Main.java

Main.java

copy
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 etter at deres forsinkelse har utløpt.

DelayedElement.java

DelayedElement.java

DelayQueueConstructors.java

DelayQueueConstructors.java

copy
123456789101112131415161718
class 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 koden demonstrerer bruken av DelayedElement-klassen, som implementerer Delayed-interface, og forsinket kø (DelayQueue) i Java. DelayedElement-klassen definerer en getDelay-metode for å beregne gjenværende forsinkelsestid og en compareTo-metode for å sammenligne objekter basert på utløpstid for forsinkelse.

main-metoden oppretter to køer: queue1, en tom forsinket kø, og queue2, en kø initialisert med elementer som har en forsinkelse på 5 og 1 sekund, henholdsvis.

Elementene i DelayQueueue blir tilgjengelige for henting etter at den angitte forsinkelsestiden har utløpt.

SynchronousQueueue: En kø uten kapasitet, der hver innsettingsoperasjon må vente på den tilsvarende uttaksoperasjonen og omvendt.

Main.java

Main.java

copy
12345
// Constructor without fair access BlockingQueue<String> queue1 = new SynchronousQueue<>(); // Constructor with fair access BlockingQueue<String> queue2 = new SynchronousQueue<>(true);

Hovedmetodene til BlockingQueue:

Legge til elementer:

Metoden void put(E e) setter inn et element i køen, og blokkerer tråden hvis køen er full. Alternativt forsøker metoden boolean offer(E e, long timeout, TimeUnit unit) å legge til et element i køen, og venter i angitt tid hvis køen er full.

Main.java

Main.java

copy
1234567891011121314151617
public 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 eksemplet viser innsetting av to elementer i en BlockingQueue uten blokkering, etterfulgt av et forsøk på å legge til et tredje element med en 2-sekunders tidsavbrudd ved bruk av offer()-metoden, som vil vente dersom køen er full.

Henting av element:

Metoden E take() henter og returnerer et element fra køen, og blokkerer tråden dersom køen er tom. Alternativt forsøker metoden E poll(long timeout, TimeUnit unit) å hente et element fra køen, og venter i angitt tid dersom køen er tom.

Main.java

Main.java

copy
1234567891011121314151617181920212223
public 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 koden legger til to elementer i en BlockingQueue, henter ut og fjerner det første elementet umiddelbart, forsøker å hente ut neste element med en 2-sekunders tidsavbrudd, og prøver til slutt å hente ut et element fra en tom kø, noe som resulterer i null etter tidsavbruddet.

Kontrollere og fjerne elementer:

Metoden boolean remove(Object o) fjerner det spesifiserte elementet fra køen dersom det er til stede. På den annen side kontrollerer metoden boolean contains(Object o) om det spesifiserte elementet finnes i køen uten å fjerne det.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526
public 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 koden legger til to elementer i en BlockingQueue, sjekker om "Element 1" er til stede, fjerner det, sjekker igjen for å bekrefte at det er fjernet, og forsøker deretter å fjerne et ikke-eksisterende element.

Spørring om køens tilstand:

Metoden int size() returnerer antall elementer som for øyeblikket er i køen. For å avgjøre om køen er tom, kan du bruke metoden boolean isEmpty(), som sjekker om køen ikke inneholder noen elementer. For køer med fast kapasitet gir metoden int remainingCapacity() antall gjenværende ledige plasser i køen.

Main.java

Main.java

copy
123456789101112131415161718192021222324252627282930
public 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 koden legger til elementer i en BlockingQueue, sjekker nåværende størrelse, verifiserer om køen er tom, og fastslår gjenværende kapasitet, deretter oppdateres disse verdiene etter at køen er fylt helt opp.

Realisere et virkelighetsnært eksempel i kode

😭 Begrensninger

En sentral begrensning er ytelse: på grunn av låseoperasjoner kan ytelsen reduseres sammenlignet med ikke-synkroniserte samlinger. I tillegg kan ressurser bli et problem ettersom store køer krever mer minne og prosessor-tid for å håndtere låser og synkroniseringsprosesser.

💪 Fordeler

På den positive siden er systemet trygt i flertrådsmiljø, og gir sikker kommunikasjon mellom tråder uten behov for manuell synkroniseringshåndtering. Det forenkler også koden ved å unngå komplekse synkroniserings- og blokkeringskonstruksjoner. Videre gir fleksibiliteten til ulike BlockingQueue-implementasjoner mulighet for tilpasning til ulike bruksscenarier.

1. Hva er en BlockingQueue i Java?

2. Hva er hovedmetodene i BlockingQueue som blokkerer en tråd?

3. Hva er BlockingQueue nyttig for i flertrådede applikasjoner?

question mark

Hva er en BlockingQueue i Java?

Select the correct answer

question mark

Hva er hovedmetodene i BlockingQueue som blokkerer en tråd?

Select the correct answer

question mark

Hva er BlockingQueue nyttig for i flertrådede applikasjoner?

Select the correct answer

Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 2. Kapittel 3
some-alt