09 | 队列:队列在线程池等有限资源池中的应用
隊列定義
先進者先出,這就是典型的“隊列”。隊列跟棧一樣,也是一種操作受限的線性表數據結構。
順序隊列和鏈式隊列
- 順序隊列:用數組實現的隊列
問題一:經過不停的入隊,出隊操作,tail指針移動到最右邊時如何處理?
數據搬移:每次出隊操作相當于刪除數組下標為0的數據,搬移一次,這樣操作的時間復雜度為O(n);
優化方案:如果沒有空閑空間了,我們只需要在入隊時,再集中觸發一次數據的搬移操作。操作時間復雜度為O(1)
數組實現的非循環隊列特征:在用數組實現的非循環隊列中,隊滿的判斷條件是 tail == n,隊空的判斷條件是 head == tail。
// 入隊操作,將item放入隊尾public boolean enqueue(String item) {// tail == n表示隊列末尾沒有空間了if (tail == n) {// tail ==n && head==0,表示整個隊列都占滿了if (head == 0) return false;// 數據搬移for (int i = head; i < tail; ++i) {items[i-head] = items[i];}// 搬移完之后重新更新head和tailtail -= head;head = 0;}items[tail] = item;++tail;return true;}- 鏈式隊列:用鏈表實現的隊列:基于鏈表的實現,我們同樣需要兩個指針:head 指針和 tail 指針。它們分別指向鏈表的第一個結點和最后一個結點。如圖所示,入隊時,tail->next= new_node, tail = tail->next;出隊時,head = head->next;
- 循環隊列:數組來實現隊列的時候,在 tail==n 時,會有數據搬移操作,如何避免數據搬移?——用循環隊列
循環隊列的難點:確定好隊空和隊滿的判定條件
那針對循環隊列,如何判斷隊空和隊滿呢?隊列為空的判斷條件仍然是 head == tail。
隊列滿的條件:(tail+1)%n=head。你有沒有發現,當隊列滿時,圖中的 tail 指向的位置實際上是沒有存儲數據的。循環隊列會浪費一個數組的存儲空間。
循環隊列的實現代碼:注意其中的?tail = (tail + 1) % n;? ? head = (head+1)%n;
public class CircularQueue {// 數組:items,數組大小:nprivate String[] items;private int n = 0;// head表示隊頭下標,tail表示隊尾下標private int head = 0;private int tail = 0;// 申請一個大小為capacity的數組public CircularQueue(int capacity) {items = new String[capacity];n = capacity;}// 入隊public boolean enqueue(String item) {// 隊列滿了if ((tail + 1) % n == head) return false;items[tail] = item;tail = (tail + 1) % n;return true;}// 出隊public String dequeue() {// 如果head == tail 表示隊列為空if (head == tail) return null;String ret = items[head];head = (head + 1) % n;return ret;} }阻塞隊列和并發隊列
阻塞隊列:在隊列為空的時候,從隊頭取數據會被阻塞;如果隊列已經滿了,那么插入數據的操作就會被阻塞,直到隊列中有空閑位置后再插入數據,然后再返回。“生產者 - 消費者模型”!是的,我們可以使用阻塞隊列,輕松實現一個“生產者 - 消費者模型”!
基于阻塞隊列,我們還可以通過協調“生產者”和“消費者”的個數,來提高數據的處理效率。比如前面的例子,我們可以多配置幾個“消費者”,來應對一個“生產者”。
并發隊列
如何實現一個線程安全的隊列?簡單粗暴的方式是直接在enqueue()、dequeue()方法上直接加鎖;但是并發度較低;
對于基于數組的循環隊列,利用cas操作可以實現更高效的并發;
循環隊列比鏈式隊列的應用廣泛;
總結:
線程池沒有空閑線程時,新的任務請求線程資源時,線程池該如何處理?各種處理策略又是如何實現的呢?
兩種處理策略:一種是非阻塞的處理方式,直接拒絕該請求;一種是阻塞的處理方式,將請求排隊,等有空閑線程時再取出進行處理;
隊列適應于存儲排隊請求。基于鏈表和基于數組的實現:基于鏈表的支持無限隊列的無界排隊,但是會導致過多的請求排隊等待,造成響應時間過長,針對響應時間比較敏感的系統,基于鏈表實現的無限排隊的線程池是不合適的。;而基于數組的隊列的大小有限,所以線程池中排隊的請求超過隊列大小時,接下來的請求就會被拒絕,這種方式對響應時間敏感的系統來說,就相對更加合理。關鍵的是設置一個合理的隊列大小。
實際上,對于大部分有限資源的場景,當沒有空閑資源基本都可以通過隊列的數據結構來實現請求排隊。例如數據庫連接池
?
?
總結
以上是生活随笔為你收集整理的09 | 队列:队列在线程池等有限资源池中的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python计算器函数图像_Python
- 下一篇: 天天生鲜页面设计——网站首页