堵塞佇列之ArrayBlockingQueue和LinkedBlockingQueue解析
線上程池建立的時候,需要傳一個堵塞佇列來維護需要執行的執行緒任務,其中最常用的是ArrayBlockingQueue和LinkedBlockingQueue。他們都繼承了BlockingQueue介面。
ArrayBlockingQueue
一個有邊界的堵塞佇列,內部使用了一個佇列來儲存元素,有takeIndex和putIndex來維護佇列頭和尾部的遊標。
/** The queued items */
//儲存元素的陣列
final Object[] items;
/** items index for next take, poll, peek or remove */
int takeIndex;
/** items index for next put, offer, or add */
int putIndex;
/** Number of elements in the queue */
int count;
/** Main lock guarding all access */
//在取和存元素的時候會進行加鎖
final ReentrantLock lock;
/** Condition for waiting takes */
//在take的時候,如果陣列為空,進行堵塞,直到陣列不為空
private final Condition notEmpty;
/** Condition for waiting puts */
//在poll的時候,如果陣列滿了,進行堵塞,直到陣列有空位
private final Condition notFull;
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
//使用鎖,預設的會使用ReentrantLock的公平鎖
//公平鎖不先嚐試獲取鎖,直接放入AQS等待佇列裡,不公平鎖會先嚐試是否可以獲取鎖,失敗才會進入等待佇列(具體實現可以檢視ReentrantLock原始碼)
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
新增資料可以使用offer和put方法,兩個區別是offer是實現Queue的方法,在佇列滿時候返回false,不進行其他操作。而put是實現了父類BlockingQueue的方法,在佇列滿的時候會通過notFull.await();進行堵塞,知道佇列有空位的時候後再進行判斷。
刪除也是同理,poll是實現Queue的方法,在佇列為空的時候不進行任何操作,take是實現BlockingQueue的方法,在佇列空的的時候會進行堵塞。
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//注意這個while,要不堵塞後還是需要進行判斷
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
//取出資料
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
當佇列新增資料的時候,先會上鎖,然後呼叫enqueue方法新增元素。
當佇列刪除資料的時候,還是會先上鎖,然後呼叫dequeue刪除元素,其中會把items[takeIndex]置為null,這樣有助於gc,防止記憶體溢位。
其中putIndex和takeIndex和最大的長度一致時,會變為0,形成一個環,使佇列可以迴圈使用。
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal();
}
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
return x;
}
LinkedBlockingQueue
LinkedBlockingQueue和ArrayBlockingQueue相比最大的不同是他可以作為一個無邊界的堵塞佇列,他的內部使用的連結串列的形式來儲存元素。
//內部定義了一個很簡單的Node節點來儲存資料。
static class Node<E> {
E item;
/**
* One of:
* - the real successor Node
* - this Node, meaning the successor is head.next
* - null, meaning there is no successor (this is the last node)
*/
Node<E> next;
Node(E x) { item = x; }
}
其次,其內部分別定義了讀寫鎖來對寫和讀進行加鎖操作,這樣相比一個鎖的好處是細化了鎖的跨度,讀寫分離,減小了鎖的競爭。
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
思考了下為什麼ArrayBlockingQueue只用了一個鎖的?我的理解是LinkedBlockingQueue是由連結串列組成操作的分別是頭尾節點,相互競爭的關係較小。而ArrayBlockingQueue是陣列,新增和刪除都是在同一個陣列上,雖然也可以用兩個鎖但是實現上需要更多的控制。
相關推薦
堵塞佇列之ArrayBlockingQueue和LinkedBlockingQueue解析
線上程池建立的時候,需要傳一個堵塞佇列來維護需要執行的執行緒任務,其中最常用的是ArrayBlockingQueue和LinkedBlockingQueue。他們都繼承了BlockingQueue介面。 ArrayBlockingQueue 一個有邊
併發容器之ArrayBlockingQueue和LinkedBlockingQueue實現原理詳解
1. ArrayBlockingQueue簡介 在多執行緒程式設計過程中,為了業務解耦和架構設計,經常會使用併發容器用於儲存多執行緒間的共享資料,這樣不僅可以保證執行緒安全,還可以簡化各個執行緒操作。例如在“生產者-消費者”問題中,會使用阻塞佇列(Blocki
JUC之ArrayBlockingQueue和LinkedBlockingQueue
部分摘抄自 阻塞佇列 在JDK中,LinkedList或ArrayList就是佇列。但是實際使用者並不多。 阻塞佇列與我們平常接觸的普通佇列(LinkedList或ArrayList等)的最大不同點,在於阻塞佇列支出阻塞新增和阻塞刪除方法。 阻
java併發佇列之ArrayBlockingQueue、LinkedBlockingQueue
ArrayBlockingQueue和LinkedBlockingQueue用法上沒有什麼區別,所以就放在一起把。 特點:阻塞佇
阻塞佇列BlockingQueue以及它的兩個重要實現類ArrayBlockingQueue和LinkedBlockingQueue
多執行緒環境中,通過佇列可以很容易實現資料共享,比如經典的“生產者”和“消費者”模型中,通過佇列可以很便利地實現兩者之間的資料共享。假設我們有若干生產者執行緒,另外又有若干個消費者執行緒。如果生產者執行緒需要把準備好的資料共享給消費者執行緒,利用佇列的方式來傳遞資料,就可以很方便地解決他們之間的資料
ArrayBlockingQueue和LinkedBlockingQueue原始碼解析
ArrayBlockingQueue和LinkedBlockingQueue都是java.util.concurrent包中的阻塞佇列。阻塞佇列就是支援阻塞的插入和移除的容量,即在容量滿時往BlockingQueue中新增資料時會造成阻塞,當容量為空時取元素操作會阻塞。內部的
ArrayBlockingQueue和LinkedBlockingQueue
分離 一個人 高效 一個 模型 空間 非阻塞 其中 影響 1、BlockingQueue接口定義了一種阻塞的FIFO queue ArrayBlockingQueue和LinkedBlockingQueue的區別: 1. 隊列中鎖的實現不同 ArrayBlockin
python爬蟲之xpath和lxml解析內容
上兩章說了urllib和request庫如何訪問一個頁面或者介面,從而獲取資料,如果是訪問介面,還好說,畢竟返回的json還是很好解析的,他是結構化的,我們可以把它轉化成字典來解析,但是如果返回的是xml或者html,就有點麻煩了,今天就主要說一下如果解析這些h
JDK原始碼分析—— ArrayBlockingQueue 和 LinkedBlockingQueue
招賢納士: 我們叫數瀾 我們核心技術團隊來自阿里、華為、金蝶、移動、GE等 我們獲得來自阿里巴巴集團聯合創始人、湖畔山南總裁謝世煌、IDG合夥人牛奎光、洪泰等投資 我們的官網:https://www.dtwave.com 我們提供:期權、五險一金、試用期全薪、商業保險、免
小BO學習筆記之ConcurrentLinkedQueue和LinkedBlockingQueue的使用比較
使用環境: 在Java多執行緒應用中,佇列的使用率很高,多數生產消費模型的首選資料結構就是佇列(先進先出)。Java提供的執行緒安全的Queue可以分為阻塞佇列和非阻塞佇列,其中阻塞佇列的典型例子是BlockingQueue,非阻塞佇列的典型例子是Concu
ArrayBlockingQueue和LinkedBlockingQueue的區別及使用
BlockingQueue介面定義了一種阻塞的FIFO queue,每一個BlockingQueue都有一個容量,讓容量滿時往BlockingQueue中新增資料時會造成阻塞,當容量為空時取元素操作會阻塞。 ArrayBlockingQueue是一個由陣列支援的有界阻塞佇
第五章 SpringMVC之ViewResolver和View解析
過完年了,本來是想在年前將SpringMVC系列寫完的,只是在接近年末的時候沒有了一種學習心態,這兩天看了一下ViewResolver原始碼,就想盡快將這篇部落格寫出,也好完結SpringMVC的系列部落格並開始下面的學習。 自己寫的
Java併發包原始碼學習系列:阻塞佇列實現之ArrayBlockingQueue原始碼解析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java之dom4j的簡單解析和生成xml的應用
util 讀寫 pro artifact gettext depend bject sta rgs 一、dom4j是一個Java的XML API,是jdom的升級品,用來讀寫XML文件的。dom4j是一個十分優秀的JavaXML API,具有性能優異、功能強大和極其易使
Django之url上的include,URL命名和反向解析,命名空間 以及圖書管理系統刪除功能二合一方法
實例 系統 code 應用 兩個 exce app number 管理系統 include其他的URLconfs #At any point, your urlpatterns can “include” other URLconf modules. This #es
資料結構JAVA版之棧和佇列
一、涉及的內容大綱 二、簡單介紹棧、佇列和其他資料結構的不同 1 對於其他的資料結構而言,都適用與資料庫應用中作資料記錄。但是因為棧和佇列的生命週期比那些資料庫型別的資料結構要短,所以他們只是在程式的操作期間才會建立和執行,在完成任務之後就會被銷燬。所以棧和佇列更多的是用於構思演算法的
訊息佇列之RabbitMQ - 簡介和安裝
訊息佇列:是簡單的生產者和消費者模式,它的出現是讓各個服務板塊之間解耦和訊息通知。比如,我們一般生成服務板塊中的資料存在有:資料庫,靜態檔案,搜尋系統,hdfs等,那麼如果資料庫中的資料發生了變化,怎麼把這個訊息推送給其他的資料儲存單元呢?如果單
輕鬆理解 - 中高階java開發必知必會 之 掌握 java阻塞隊(ArrayBlockingQueue與LinkedBlockingQueue)
在java開發中有些特殊場景下適用於阻塞佇列如: 多執行緒環境中,通過佇列可以很容易實現資料共享,比如經典的“生產者”和“消費者”模型中,通過佇列可以很便利地實現兩者之間的資料共享。假設我們有若干生產者執行緒,另外又有若干個消費者執行緒。如果生產者執行緒需要把準備好的資料共享給消費者執行緒,利用
原始碼解析關於java阻塞容器:ArrayBlockingQueue,LinkedBlockingQueue等
Java的阻塞容器介紹JDK18 一ArrayBlockingQueue 類的定義 重要的成員變數 初始化 一些重要的非公開的方法
Android複習之旅--XML序列化和pull解析
對於XML是什麼,這裡就不多說了,如果不懂可以google學習下。 xml是非常重要和常用的一種資料格式 XML序列化 步驟: 生成一個序列化器 XmlSerializer serializer = Xml.newSerializer(); 要