Queue: Basically, a queue is a FIFO data structure
The Queue interface, at the same level as List and Set, inherits the Collection interface. LinkedList implements the Deque interface.
Implementation of Queue
1. LinkedList with Implemented Blocking Interface: Implemented java.util.Queue Interface and java.util.AbstractQueue Interface
Built-in non-blocking queues: PriorityQueue and Concurrent LinkedQueue
The PriorityQueue and ConcurrentLinkedQueue classes add two specific collection implementations to the Collection Framework.
The PriorityQueue class essentially maintains an ordered list. Elements added to Queue are positioned according to their natural ordering (through their java.util.Comparable implementation) or by the java.util.Comparator implementation passed to the constructor.
Concurrent LinkedQueue is a thread-safe queue based on linked nodes. Concurrent access does not require synchronization. Because it adds elements at the end of the queue and removes them from the head, Concurrent LinkedQueue's shared access to public collections works well as long as the queue size is not known. Collecting information about queue size is slow and requires traversing the queue.
2. Implementing blocking interfaces:
BlockingQueue interface and five blocking queue classes are added to java.util.concurrent. It is essentially a FIFO data structure with a little distortion. Instead of immediately adding or deleting elements from the queue, threads perform operations that block until there is space or elements are available.
The five queues provide different information:
- Array BlockingQueue: A bounded queue supported by an array.
- Linked Blocking Queue: An optionally bounded queue supported by link nodes.
- Priority Blocking Queue: An unbounded priority queue supported by a priority heap.
- DelayQueue: A time-based scheduling queue supported by a priority heap.
- SynchronousQueue: A simple rendezvous mechanism using the BlockingQueue interface.
3. Main methods:
If the queue is full, a IIIegaISlabEepeplian exception is thrown
remove the element at the head of the queue and return it. If the queue is empty, a NoSuchElementException exception is thrown
If the queue is empty, a NoSuchElementException exception is thrown
Add an element and return true. If the queue is full, return false
Remove and ask back the elements at the head of the queue. If the queue is empty, return null
peek) Returns the element at the head of the queue. If the queue is empty, null is returned.
put * Add an element * Block if the queue is full
take. Remove and return the element at the head of the queue. Block if the queue is empty
4. Detailed explanation of four queues
(1) LinkedBlockingQueue has unlimited capacity (inaccurate, Integer.MAX_VALUE capacity is not specified, otherwise how can it be blocked when put ting), but you can also choose to specify its maximum capacity, which is a linked list-based queue, which ranks elements according to FIFO (first in first out).
(2) Array BlockingQueue needs to specify its capacity when it is constructed and can choose whether it needs fairness. If the fairness parameter is set to true, the thread with the longest waiting time will be processed first (in fact, this fairness is achieved by setting ReentrantLock to true: the thread with the longest waiting time will operate first). Usually, fairness will cost you performance, and only use it when you really need it. It is based on an array of blocking loop queues, which sort elements according to FIFO (first in first out) principle.
(3) Priority Blocking Queue is a priority queue, not a first-in-first-out queue. Elements are removed in priority order and the queue has no upper bound. (Looking at the source code, Priority Blocking Queue is a re-wrapping of Priority Queue based on heap data structure, while Priority Queue is capacity-free, like ArrayList, so it is not blocked when put ting on a priority blocked queue. Although this queue is logically unbounded, because resources are exhausted, an attempt to perform an add operation may result in OutOfMemoryError, but if the queue is empty, the take-up operation of the element will block, so its search operation take-up is blocked. In addition, the elements entering the queue should have comparative ability.
(4) DelayQueue (based on PriorityQueue) is an unbounded blocking queue that stores Delayed elements and extracts elements only when the delay expires. The head of the queue is the Delayed element that lasts the longest after the delay expires. If the delay has not expired, the queue has no head, and poll returns null. When the getDelay(TimeUnit.NANOSECONDS) method of an element returns a value less than or equal to zero, the expiration occurs and poll removes the element. Null elements are not allowed in this queue.
5. Code examples
package is.data.structure.queue; import java.time.Duration; import java.time.Instant; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingDeque; /** * @ClassName: FruitBasket * @Description: * Fruits Basket * @Author: Coding_wxb */ public class FruitBasket { private boolean close = false; BlockingQueue<Fruit> basket = new LinkedBlockingDeque<>(10); //Fruit storage public void storeFruit(Fruit fruit) throws InterruptedException{ basket.put(fruit); } //Remove fruit public Fruit getFruit() throws InterruptedException{ return basket.take(); } //Get the number of fruits in the basket public int getSize(){ return basket.size(); } //Fruit producers class Producer implements Runnable{ @Override public void run() { try { while (!close){ System.out.println("Producers began to produce fruit:"); Instant start = Instant.now(); Fruit fruit1 = new Fruit("read","apple"); Fruit fruit2 = new Fruit("yellow","pear"); storeFruit(fruit1); storeFruit(fruit2); Instant end = Instant.now(); System.out.println("Total time-consuming for fruit production:"+Duration.between(start,end).toMillis()); System.out.println("After fruit production, there are:"+getSize()+"A fruit"); Thread.sleep(3000); } }catch (Throwable e){ e.printStackTrace(); } } } //Fruit consumers class Consumer implements Runnable{ @Override public void run() { try { while (!close){ System.out.println("Consumers began to consume fruit:"); Instant start = Instant.now(); Fruit fruit = getFruit(); System.out.println("The consumption of fruits is as follows:"+fruit.toString()); System.out.println("After fruit production, there are:"+getSize()+"A fruit"); Instant end = Instant.now(); System.out.println("Consumption of fruit takes time:"+Duration.between(start,end).toMillis()); Thread.sleep(3000); } }catch (Throwable e){ e.printStackTrace(); } } } public void test(){ ExecutorService ex = Executors.newCachedThreadPool(); Producer producer = new Producer(); Consumer consumer = new Consumer(); ex.submit(producer); ex.submit(consumer); //The program runs for ten seconds. try { Thread.sleep(10000); }catch (Throwable e){ e.printStackTrace(); } ex.shutdownNow(); } public static void main(String[] args) { FruitBasket basket = new FruitBasket(); basket.test(); } //Fruits class Fruit{ private String color; private String name; public Fruit(String color, String name) { this.color = color; this.name = name; } @Override public String toString() { return "Fruit{" + "color='" + color + '\'' + ", name='" + name + '\'' + '}'; } } }