Blockingqueue 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 kö, 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.
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
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);
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
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
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
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); } }
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
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
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(); } } }
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
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(); } } }
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
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(); } } }
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
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(); } } }
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?
Tack för dina kommentarer!
Fråga AI
Fråga AI
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
Blockingqueue 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 kö, 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.
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
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);
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
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
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
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); } }
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
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
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(); } } }
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
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(); } } }
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
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(); } } }
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
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(); } } }
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?
Tack för dina kommentarer!