Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lära Blockingqueue och Dess Implementationer | Synkroniserade Samlingar
Multitrådning i Java

bookBlockingqueue och Dess Implementationer

Grundläggande BlockingQueue-implementationer

Vi kommer inte att gå igenom varje implementation i detalj, eftersom det skulle ta mycket tid och det är osannolikt att du behöver dem alla. Jag kommer att ta upp de allmänna koncepten och vilka konstruktorer de har.

Exempel från verkligheten

Föreställ dig en fabrik där en tråd, producenten, skapar delar och en annan tråd, konsumenten, bearbetar dem. Producenten lägger delarna i en , medan konsumenten hämtar och bearbetar dem från kön. Om kön tar slut på delar väntar konsumenten på att producenten ska lägga till fler. Omvänt, om kön är full, väntar producenten på att konsumenten ska frigöra utrymme.

Note
Notering

Lite längre ner kommer vi att implementera denna uppgift i kod.

Skillnader från andra samlingstyper

BlockingQueue tillhandahåller automatisk synkronisering och hanterar trådars åtkomst till kön utan att manuell synkronisering krävs. Den stöder även blockerande operationer för att lägga till och hämta objekt, en funktion som inte finns i andra samlingar som ArrayList eller LinkedList.

BlockingQueue-implementationer

ArrayBlockingQueue: En storleksbegränsad kö som använder en array för att lagra objekt.

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
Notera

Parametern true möjliggör en rättvis åtkomstpolicy genom att tillhandahålla en FIFO-ordning för trådåtkomst.

LinkedBlockingQueueue: En kö baserad på länkade noder som kan vara begränsad eller obegränsad.

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 obunden prioriterad kö där element hämtas enligt deras naturliga ordning eller enligt en angiven 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 fördröjd kö där objekt endast kan hämtas efter att deras fördröjning har löpt ut.

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); } }

Denna kod illustrerar användningen av klassen DelayedElement, som implementerar interfacet Delayed, samt den fördröjda kön DelayQueue i Java. Klassen DelayedElement definierar en metod getDelay för att beräkna återstående fördröjningstid och en metod compareTo för att jämföra objekt baserat på förfallotid för fördröjning.

Metoden main skapar två köer: queue1, en tom fördröjd kö, och queue2, en kö som initieras med element som har en fördröjning på 5 respektive 1 sekund.

Objekten i DelayQueueue blir tillgängliga för hämtning efter att den angivna fördröjningstiden har passerat.

SynchronousQueueue: En kö utan kapacitet, där varje infogningsoperation måste vänta på motsvarande uttagsoperation och vice versa.

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);

De viktigaste metoderna för BlockingQueue:

Lägga till element:

Metoden void put(E e) infogar ett objekt i kön och blockerar tråden om kön är full. Alternativt försöker metoden boolean offer(E e, long timeout, TimeUnit unit) lägga till ett objekt i kön och väntar under angiven tid om kön är 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(); } } }

Detta exempel visar hur två element infogas i en BlockingQueue utan blockering, följt av ett försök att lägga till ett tredje element med en 2 sekunders timeout med hjälp av metoden offer(), som väntar om kön är full.

Hämtning av element:

Metoden E take() hämtar och returnerar ett objekt från kön, och blockerar tråden om kön är tom. Alternativt försöker metoden E poll(long timeout, TimeUnit unit) hämta ett objekt från kön, och väntar under angiven tid om kön är 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(); } } }

Denna kod lägger till två element i en BlockingQueue, hämtar och tar bort det första elementet omedelbart, försöker hämta nästa element med en 2-sekunders timeout, och försöker slutligen hämta ett element från en tom kö, vilket resulterar i null efter timeouten.

Kontrollera och ta bort element:

Metoden boolean remove(Object o) tar bort det angivna elementet från kön om det finns. Å andra sidan kontrollerar metoden boolean contains(Object o) om det angivna elementet finns i kön utan att ta bort 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(); } } }

Denna kod lägger till två element i en BlockingQueue, kontrollerar om "Element 1" finns, tar bort det, kontrollerar igen för att bekräfta borttagningen och försöker sedan ta bort ett icke-existerande element.

Kontrollerar köstatus:

Metoden int size() returnerar antalet element som för närvarande finns i kön. För att avgöra om kön är tom kan du använda metoden boolean isEmpty(), som kontrollerar om kön saknar element. För köer med fast kapacitet ger metoden int remainingCapacity() antalet återstående tillgängliga platser i kön.

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(); } } }

Denna kod lägger till element i en BlockingQueue, kontrollerar nuvarande storlek, verifierar om kön är tom, och fastställer återstående kapacitet, och uppdaterar sedan dessa värden efter att kön har fyllts helt.

Realisera ett verkligt exempel i kod

😭 Begränsningar

En viktig begränsning är prestanda: på grund av låsoperationerna kan prestandan minska jämfört med icke-synkroniserade samlingar. Dessutom kan resurser bli ett problem eftersom stora köer kräver mer minne och CPU-tid för att hantera lås och synkroniseringsprocesser.

💪 Fördelar

På den positiva sidan är systemet säkert vid multitrådning, vilket möjliggör säker kommunikation mellan trådar utan att man behöver hantera synkronisering manuellt. Det förenklar även koden genom att undvika komplex synkronisering och blockering. Dessutom innebär flexibiliteten hos olika BlockingQueue-implementationer att de kan anpassas till olika användningsområden.

1. Vad är en BlockingQueue i Java?

2. Vilka är de huvudsakliga metoderna i BlockingQueue som blockerar en tråd?

3. Vad är BlockingQueue användbar för i multitrådade applikationer?

question mark

Vad är en BlockingQueue i Java?

Select the correct answer

question mark

Vilka är de huvudsakliga metoderna i BlockingQueue som blockerar en tråd?

Select the correct answer

question mark

Vad är BlockingQueue användbar för i multitrådade applikationer?

Select the correct answer

Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 2. Kapitel 3

Fråga AI

expand

Fråga AI

ChatGPT

Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal

Awesome!

Completion rate improved to 3.33

bookBlockingqueue och Dess Implementationer

Svep för att visa menyn

Grundläggande BlockingQueue-implementationer

Vi kommer inte att gå igenom varje implementation i detalj, eftersom det skulle ta mycket tid och det är osannolikt att du behöver dem alla. Jag kommer att ta upp de allmänna koncepten och vilka konstruktorer de har.

Exempel från verkligheten

Föreställ dig en fabrik där en tråd, producenten, skapar delar och en annan tråd, konsumenten, bearbetar dem. Producenten lägger delarna i en , medan konsumenten hämtar och bearbetar dem från kön. Om kön tar slut på delar väntar konsumenten på att producenten ska lägga till fler. Omvänt, om kön är full, väntar producenten på att konsumenten ska frigöra utrymme.

Note
Notering

Lite längre ner kommer vi att implementera denna uppgift i kod.

Skillnader från andra samlingstyper

BlockingQueue tillhandahåller automatisk synkronisering och hanterar trådars åtkomst till kön utan att manuell synkronisering krävs. Den stöder även blockerande operationer för att lägga till och hämta objekt, en funktion som inte finns i andra samlingar som ArrayList eller LinkedList.

BlockingQueue-implementationer

ArrayBlockingQueue: En storleksbegränsad kö som använder en array för att lagra objekt.

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
Notera

Parametern true möjliggör en rättvis åtkomstpolicy genom att tillhandahålla en FIFO-ordning för trådåtkomst.

LinkedBlockingQueueue: En kö baserad på länkade noder som kan vara begränsad eller obegränsad.

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 obunden prioriterad kö där element hämtas enligt deras naturliga ordning eller enligt en angiven 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 fördröjd kö där objekt endast kan hämtas efter att deras fördröjning har löpt ut.

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); } }

Denna kod illustrerar användningen av klassen DelayedElement, som implementerar interfacet Delayed, samt den fördröjda kön DelayQueue i Java. Klassen DelayedElement definierar en metod getDelay för att beräkna återstående fördröjningstid och en metod compareTo för att jämföra objekt baserat på förfallotid för fördröjning.

Metoden main skapar två köer: queue1, en tom fördröjd kö, och queue2, en kö som initieras med element som har en fördröjning på 5 respektive 1 sekund.

Objekten i DelayQueueue blir tillgängliga för hämtning efter att den angivna fördröjningstiden har passerat.

SynchronousQueueue: En kö utan kapacitet, där varje infogningsoperation måste vänta på motsvarande uttagsoperation och vice versa.

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);

De viktigaste metoderna för BlockingQueue:

Lägga till element:

Metoden void put(E e) infogar ett objekt i kön och blockerar tråden om kön är full. Alternativt försöker metoden boolean offer(E e, long timeout, TimeUnit unit) lägga till ett objekt i kön och väntar under angiven tid om kön är 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(); } } }

Detta exempel visar hur två element infogas i en BlockingQueue utan blockering, följt av ett försök att lägga till ett tredje element med en 2 sekunders timeout med hjälp av metoden offer(), som väntar om kön är full.

Hämtning av element:

Metoden E take() hämtar och returnerar ett objekt från kön, och blockerar tråden om kön är tom. Alternativt försöker metoden E poll(long timeout, TimeUnit unit) hämta ett objekt från kön, och väntar under angiven tid om kön är 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(); } } }

Denna kod lägger till två element i en BlockingQueue, hämtar och tar bort det första elementet omedelbart, försöker hämta nästa element med en 2-sekunders timeout, och försöker slutligen hämta ett element från en tom kö, vilket resulterar i null efter timeouten.

Kontrollera och ta bort element:

Metoden boolean remove(Object o) tar bort det angivna elementet från kön om det finns. Å andra sidan kontrollerar metoden boolean contains(Object o) om det angivna elementet finns i kön utan att ta bort 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(); } } }

Denna kod lägger till två element i en BlockingQueue, kontrollerar om "Element 1" finns, tar bort det, kontrollerar igen för att bekräfta borttagningen och försöker sedan ta bort ett icke-existerande element.

Kontrollerar köstatus:

Metoden int size() returnerar antalet element som för närvarande finns i kön. För att avgöra om kön är tom kan du använda metoden boolean isEmpty(), som kontrollerar om kön saknar element. För köer med fast kapacitet ger metoden int remainingCapacity() antalet återstående tillgängliga platser i kön.

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(); } } }

Denna kod lägger till element i en BlockingQueue, kontrollerar nuvarande storlek, verifierar om kön är tom, och fastställer återstående kapacitet, och uppdaterar sedan dessa värden efter att kön har fyllts helt.

Realisera ett verkligt exempel i kod

😭 Begränsningar

En viktig begränsning är prestanda: på grund av låsoperationerna kan prestandan minska jämfört med icke-synkroniserade samlingar. Dessutom kan resurser bli ett problem eftersom stora köer kräver mer minne och CPU-tid för att hantera lås och synkroniseringsprocesser.

💪 Fördelar

På den positiva sidan är systemet säkert vid multitrådning, vilket möjliggör säker kommunikation mellan trådar utan att man behöver hantera synkronisering manuellt. Det förenklar även koden genom att undvika komplex synkronisering och blockering. Dessutom innebär flexibiliteten hos olika BlockingQueue-implementationer att de kan anpassas till olika användningsområden.

1. Vad är en BlockingQueue i Java?

2. Vilka är de huvudsakliga metoderna i BlockingQueue som blockerar en tråd?

3. Vad är BlockingQueue användbar för i multitrådade applikationer?

question mark

Vad är en BlockingQueue i Java?

Select the correct answer

question mark

Vilka är de huvudsakliga metoderna i BlockingQueue som blockerar en tråd?

Select the correct answer

question mark

Vad är BlockingQueue användbar för i multitrådade applikationer?

Select the correct answer

Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 2. Kapitel 3
some-alt