日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

09 | 队列:队列在线程池等有限资源池中的应用

發布時間:2023/12/10 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 09 | 队列:队列在线程池等有限资源池中的应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

隊列定義

先進者先出,這就是典型的“隊列”。隊列跟棧一樣,也是一種操作受限的線性表數據結構。

順序隊列和鏈式隊列

  • 順序隊列:用數組實現的隊列
// 用數組實現的隊列 public class ArrayQueue {// 數組:items,數組大小:nprivate String[] items;private int n = 0;// head表示隊頭下標,tail表示隊尾下標private int head = 0;private int tail = 0;// 申請一個大小為capacity的數組public ArrayQueue(int capacity) {items = new String[capacity];n = capacity;}// 入隊public boolean enqueue(String item) {// 如果tail == n 表示隊列已經滿了if (tail == n) return false;items[tail] = item;++tail;return true;}// 出隊public String dequeue() {// 如果head == tail 表示隊列為空if (head == tail) return null;// 為了讓其他語言的同學看的更加明確,把--操作放到單獨一行來寫了String ret = items[head];++head;return ret;} }

問題一:經過不停的入隊,出隊操作,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 | 队列:队列在线程池等有限资源池中的应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。