Java中幾個常用併發佇列比較 | Baeldung
在多執行緒應用程式中,佇列需要處理多個併發的生產者-消費者方案。正確選擇併發佇列對於在我們的演算法中實現良好效能至關重要。
首先,我們將看到阻塞佇列和非阻塞佇列之間的一些重要區別。然後,我們將看一些實現和最佳實踐。
BlockingQueue提供了一種簡單的執行緒安全機制。在此佇列中,執行緒需要等待佇列的可用性。生產者將在新增元素之前等待可用容量,而消費者將等待直到佇列為空。為了實現這種阻塞機制,BlockingQueue介面在常規Queue函式的基礎上提供了兩個函式:put和take。這些功能等效於標準Queue中的add和remove。
ArrayBlockingQueue
此佇列在內部使用陣列。因此,它是一個有界佇列,這意味著它具有固定的大小。適合生產者/消費者比率通常很低情況,我們將耗時的任務分配給多個worker。由於此佇列不能無限增長,因此如果出現記憶體問題,需要將大小限制將作為安全閾值。
ArrayBlockingQueue對put和take操作都使用一個鎖。這樣可以確保不覆蓋條目,但會降低效能。
LinkedBlockingQueue
LinkedBlockingQueue使用連結串列變體,其中每個佇列專案是一個新的節點。雖然這使佇列在原則上不受限制,但仍然具有Integer.MAX_VALUE的硬限制。我們可以使用建構函式LinkedBlockingQueue(int capacity)設定佇列大小。
佇列使用不同的鎖進行put和take操作。因此兩種操作可以並行完成並提高了吞吐量。
由於LinkedBlockingQueue可以是有界的或無界的,為什麼我們還要使用ArrayBlockingQueue?每次在佇列中新增或刪除專案時,LinkedBlockingQueue都需要分配和取消分配節點。因此,如果佇列快速增長和快速收縮,則 ArrayBlockingQueue可能是更好的選擇。
據說LinkedBlockingQueue的效能是不可預測的。換句話說,我們始終需要剖析我們的方案以確保我們使用正確的資料結構。
PriorityBlockingQueue
當我們需要按特定順序消費資料時,PriorityBlockingQueue是我們的首選解決方案。為此,PriorityBlockingQueue使用基於陣列的二進位制堆。
儘管在內部使用單個鎖定機制,但是take操作可以與put操作同時進行。使用簡單的自旋鎖可以實現這一點。
一個典型的用例是使用具有不同優先順序的任務。我們不希望低優先順序的任務代替高優先順序的任務。
DelayQueue
當使用者只能take過期的資料專案時,我們使用DelayQueue 。有趣的是,它在內部使用PriorityQueue來按資料專案的到期時間對其進行排序。
由於這不是通用佇列,因此它無法涵蓋ArrayBlockingQueue或LinkedBlockingQueue那樣多的場景。例如,我們可以使用此佇列來實現一個簡單的事件迴圈,類似於在NodeJS中找到的事件迴圈。我們將非同步任務放在佇列中,以便在它們到期時進行後續處理。
LinkedTransferQueue
LinkedTransferQueue引入一個transfer 方法。儘管其他佇列通常在生產或消費資料專案時阻塞,但LinkedTransferQueue 允許生產者等待資料專案的消費。
當我們需要保證放入佇列中的某個特定專案已被消費者take拿走時,可以使用LinkedTransferQueue。同樣,我們可以使用此佇列實現簡單的反壓演算法。實際上,透過阻止生產者直到消費,消費者可以驅動所產生的訊息流。
SynchronousQueue
普通佇列通常包含許多資料專案,但SynchronousQueue最多始終只有一個專案。換句話說,我們需要將SynchronousQueue視為在兩個執行緒之間交換某些資料的簡單方法。
當我們有兩個需要訪問共享狀態的執行緒時,我們通常將它們與CountDownLatch或其他同步機制同步。透過使用SynchronousQueue,我們可以避免執行緒的這種手動同步。
ConcurrentLinkedQueue
ConcurrentLinkedQueue是本文唯一的非阻塞佇列,因此,它提供了一種“免等待”演算法,其中add和poll保證是執行緒安全的,並立即返回。該佇列使用CAS(Compare-And-Swap)代替鎖。
在內部,它基於Maged M. Michael和Michael L. Scott的簡單,快速和實用的非阻塞和阻塞併發佇列演算法。
對於經常禁止使用阻塞資料結構的現代反應系統,它是理想的選擇。
另一方面,如果我們的消費者最終陷入迴圈等待,我們可能應該選擇阻塞佇列作為更好的選擇。
相關文章
- 有序佇列比較佇列
- Cesium 比較常用的幾個方法
- Java幾種常用JSON庫效能比較JavaJSON
- Java Optional的orElse()與orElseGet()兩個方法比較 - BaeldungJava
- Java併發佇列與容器Java佇列
- MQ 訊息佇列 比較MQ佇列
- 解讀 Java 併發佇列 BlockingQueueJava佇列BloC
- Java併發系列 — 阻塞佇列(BlockingQueue)Java佇列BloC
- Java併發——阻塞佇列集(上)Java佇列
- Java併發——阻塞佇列集(下)Java佇列
- 常用的Java開發工具比較Java
- 圖解--佇列、併發佇列圖解佇列
- 優先佇列的比較器佇列
- Java併發程式設計:阻塞佇列Java程式設計佇列
- JAVA併發之阻塞佇列淺析Java佇列
- Java併發程式設計——阻塞佇列Java程式設計佇列
- Java中陣列判斷元素存在幾種方式比較詳解Java陣列
- 併發模型比較模型
- 乾貨|解讀Java併發佇列BlockingQueueJava佇列BloC
- Java併發6:阻塞佇列,Fork/Join框架Java佇列框架
- Java併發指南11:解讀 Java 阻塞佇列 BlockingQueueJava佇列BloC
- 資料分析領域幾個常用工具比較
- Java中常用七個阻塞佇列的總結Java佇列
- 佇列的併發使用佇列
- 透徹理解Java併發的等待佇列——ConditionJava佇列
- 併發佇列ConcurrentLinkedQueue與LinkedBlockingQueue原始碼分析與對比佇列BloC原始碼
- 分割陣列的幾種方法比較陣列
- 聊聊併發(四)——阻塞佇列佇列
- Java併發(10)- 簡單聊聊JDK中的七大阻塞佇列JavaJDK佇列
- 阻塞佇列一——java中的阻塞佇列佇列Java
- Linux中11個比較實用的命令列Linux命令列
- BlockingQueue的作用以及實現的幾個常用阻塞佇列原理BloC佇列
- Java、Rust、Go、NodeJS、TypeScript併發程式設計比較 - foojayJavaRustGoNodeJSTypeScript程式設計
- 【Java 併發筆記】7 種阻塞佇列相關整理Java筆記佇列
- Java 併發程式設計 ----- AQS(抽象佇列同步器)Java程式設計AQS抽象佇列
- 10分鐘搞定 Java 併發佇列好嗎?好的Java佇列
- Java 併發程式設計 —– AQS(抽象佇列同步器)Java程式設計AQS抽象佇列
- Java中的幾種Kafka客戶端比較介紹JavaKafka客戶端