Java queue隊列接口指南
1.簡介
在本教程中,我們將討論Java的Queue接口。
首先,我們來看看**Queue的功能及其一些核心方法。接下來,我們將深入研究Java作為標準提供的許多實現。
最後,在將其全部包裝之前,我們將討論線程安全性。
2.可視化隊列
讓我們從一個快速的類比開始。
想像一下,我們剛開始我們的第一筆生意–熱狗攤。我們希望以最有效的方式為我們的小型企業服務新的潛在客戶;一次一個。首先,我們要求他們在我們的展位前排成一排,在後方加入新客戶。由於我們的組織能力,我們現在可以公平地分配美味的熱狗了。
Java中的隊列以類似的方式工作。聲明隊列後,我們可以在後面添加新元素,並從前面刪除它們。
實際上,我們在Java中遇到的大多數隊列都是以這種先進先出的方式工作的-通常縮寫為FIFO。
但是,有一個例外情況我們稍後會介紹。
3.核心方法
隊列聲明了所有實現類都需要編碼的許多方法。現在讓我們概述一些更重要**的:**
- offer() –在隊列中插入一個新元素
- poll() –從隊列的前面刪除一個元素
- *peek() –檢查隊列前面的元素,*而不刪除它
4.抽象隊列
AbstractQueue是Java提供的最簡單的Queue實現。*它包括一些Queue接口方法的基本實現,但不包括offer* 。
當我們創建擴展AbstractQueue類的定制隊列**,我們必須提供**的報價方法,它不允許null元素插入**的實現**。
另外,我們必須提供方法peek,poll,size和java.util的iterator 。
讓我們使用AbstractQueue**組合一個簡單的Queue實現**。
首先,讓我們用LinkedList定義我們的類,以存儲隊列的元素:
public class CustomBaeldungQueue<T> extends AbstractQueue<T> {
private LinkedList<T> elements;
public CustomBaeldungQueue() {
this.elements = new LinkedList<T>();
}
}
接下來,讓我們重寫所需的方法並提供代碼:
@Override
public Iterator<T> iterator() {
return elements.iterator();
}
@Override
public int size() {
return elements.size();
}
@Override
public boolean offer(T t) {
if(t == null) return false;
elements.add(t);
return true;
}
@Override
public T poll() {
Iterator<T> iter = elements.iterator();
T t = iter.next();
if(t != null){
iter.remove();
return t;
}
return null;
}
@Override
public T peek() {
return elements.getFirst();
}
太好了,讓我們檢查一下它是否可以用於快速的單元測試:
customQueue.add(7);
customQueue.add(5);
int first = customQueue.poll();
int second = customQueue.poll();
assertEquals(7, first);
assertEquals(5, second);
4.子接口
通常, Queue接口由3個主要子接口繼承*。**阻塞隊列,傳輸隊列和雙端*隊列。
這3個接口一起由Java的絕大多數可用隊列實現。讓我們快速看一下這些接口的作用。
4.1。阻塞隊列
BlockingQueue接口支持其他操作,這些操作強制線程根據當前狀態在**隊列上等待。嘗試進行檢索時,線程可以等待Queue為非空,或者在添加新元素時使其變為空。
標準阻塞隊列包括LinkedBlockingQueue,SynchronousQueue和ArrayBlockingQueue 。
有關更多信息,請轉至我們關於阻塞隊列的文章。
4.2。傳輸隊列
TransferQueue接口擴展了BlockingQueue接口,但針對生產者-消費者模式進行了定制。它控制從生產者到消費者的信息流,從而在系統中造成背壓。
Java附帶了TransferQueue接口的一種實現LinkedTransferQueue。
4.3。雙端隊列
雙端隊列為短於d ouble-Ënded***闕UE和類似於一副牌-元素可以從一開始就與雙端隊列的端兩者作出。就像傳統的Queue一樣,* **Deque提供了一些方法來添加,檢索和查看頂部和底部的元素。
有關Deque如何工作的詳細指南,請查看我們的ArrayDeque文章。
5.優先隊列
前面我們看到,Java中遇到的大多數隊列都遵循FIFO原則。
PriorityQueue是此規則的一種例外。將新元素插入到Priority Queue中時,它們將根據其自然順序或在構造Priority Queue時提供的已定義Comparator進行排序。
讓我們看一下如何使用簡單的單元測試:
PriorityQueue<Integer> integerQueue = new PriorityQueue<>();
integerQueue.add(9);
integerQueue.add(2);
integerQueue.add(4);
int first = integerQueue.poll();
int second = integerQueue.poll();
int third = integerQueue.poll();
assertEquals(2, first);
assertEquals(4, second);
assertEquals(9, third);
儘管將整數添加到Priority Queue**的順序有所不同,但我們可以看到,檢索順序根據數字的自然順序而改變。**
我們可以看到,將其應用於String時也是如此:
PriorityQueue<String> stringQueue = new PriorityQueue<>();
stringQueue.add("blueberry");
stringQueue.add("apple");
stringQueue.add("cherry");
String first = stringQueue.poll();
String second = stringQueue.poll();
String third = stringQueue.poll();
assertEquals("apple", first);
assertEquals("blueberry", second);
assertEquals("cherry", third);
6.線程安全
在多線程環境中,將項目添加到隊列特別有用。**隊列可以在線程之間共享,並且可以用來阻塞進度,直到空間可用為止–幫助我們克服了一些常見的多線程問題。**
例如,從多個線程寫入單個磁盤會造成資源爭用,並可能導致寫入時間變慢。使用BlockingQueue創建單個編寫器線程可以緩解此問題,並大大提高寫入速度。
幸運的是,Java提供了ConcurrentLinkedQueue,ArrayBlockingQueue和ConcurrentLinkedDeque ,它們是線程安全的,並且非常適合多線程程序。
7.結論
在本教程中,我們深入研究了Java Queue接口。
首先,我們探討了Queue的功能以及Java提供的實現。
接下來,我們研究了Queue的通常FIFO原理以及PriorityQueue的順序不同。
最後,我們探討了線程安全性以及如何在多線程環境中使用隊列。
與往常一樣,代碼可以 在GitHub上獲得。