隊列在有限資源池中的應(yīng)用

1. 什么是隊列蛙紫?

隊列的特點是先進(jìn)先出,有兩個基本操作:入隊(enqueue)途戒,放一個數(shù)據(jù)到隊列尾部坑傅;出隊(dequeue),從隊列頭部取一個元素棺滞。裁蚁。它和棧一樣矢渊,也是一種操作受限的線形表數(shù)據(jù)結(jié)構(gòu)继准。

隊列的應(yīng)用非常廣泛,特別是一些具有某些額外特性的隊列矮男,比如循環(huán)隊列移必、阻塞隊列、并發(fā)隊列毡鉴。它們在很多偏底層系統(tǒng)崔泵、框架、中間件的開發(fā)中猪瞬,起著關(guān)鍵性的作用憎瘸。

隊列

2. 如何實現(xiàn)隊列?

跟棧一樣陈瘦,隊列可以用數(shù)組來實現(xiàn)幌甘,也可以用鏈表來實現(xiàn)。用數(shù)組實現(xiàn)的隊列叫作順序隊列,用鏈表實現(xiàn)的隊列叫作鏈?zhǔn)疥犃?/strong>锅风。

使用數(shù)組實現(xiàn)的隊列:

public class QueueByArray<E> {
    private int size;
    private E[] data;
    private int head;
    private int tail;

    public QueueByArray() {
        this(8);
    }

    public QueueByArray(int size) {
        data = (E[]) new Object[size];
        this.size = size;
    }

    /**
     * 入隊
     *
     * @param element
     * @return
     */
    public boolean enqueue(E element) {
        // 隊尾沒有空間
        if (tail == size) {
            // 隊列已滿
            if (head == 0) {
                return false;
            }
            System.out.println("move element, head " + head + ", tail " + tail);
            // 移動元素酥诽,從尾部向首部搬移
            for (int i = head; i < tail; i++) {
                data[i - head] = data[i];
            }
            tail -= head;
            head = 0;
        }
        data[tail++] = element;
        return true;
    }

    /**
     * 出隊
     *
     * @return
     */
    public E dequeue() {
        // 隊列為空
        if (head == tail) {
            return null;
        }
        return data[head++];
    }
}

使用鏈表實現(xiàn)的隊列:

public class QueueByLink<E> {
    private int size;
    private Node head;
    private Node tail;

    /**
     * 入隊
     *
     * @param element
     */
    public void enqueue(E element) {
        if (head == null) {
            head = new Node();
            head.element = element;
            tail = head;
        } else {
            Node node = new Node();
            node.element = element;
            tail.next = node;
            tail = node;
        }
        size++;
    }

    /**
     * 出隊
     *
     * @return
     */
    public E dequeue() {
        if (head == null) {
            return null;
        }
        E element = head.element;
        head = head.next;
        size--;
        return element;
    }
  
    private class Node {
        private E element;
        private Node next;
    }
}

3. 循環(huán)隊列

循環(huán)隊列像一個環(huán),首尾相連皱埠,避免了數(shù)據(jù)移動肮帐。實現(xiàn)循環(huán)隊列的關(guān)鍵是,確定好隊空和隊滿的判定條件边器。當(dāng)隊滿時训枢,(tail+1)%n=head

下面是使用數(shù)組實現(xiàn)循環(huán)隊列:

public class CircularQueue<E> {
    // 容量
    private int size;
    private E[] data;
    private int head;
    private int tail;

    public CircularQueue() {
        this(8);
    }

    public CircularQueue(int size) {
        data = (E[]) new Object[size];
        this.size = size;
    }

    /**
     * 入隊
     *
     * @param element
     * @return
     */
    public boolean enqueue(E element) {
        // 隊列已滿
        if ((tail + 1) % size == head) {
            return false;
        }
        data[tail] = element;
        tail = (tail + 1) % size;
        return true;
    }

    /**
     * 出隊
     *
     * @return
     */
    public E dequeue() {
        // 隊列為空
        if (head == tail) {
            return null;
        }
        E ele = data[head];
        head = (head + 1) % size;
        return ele;
    }
}

4. 阻塞隊列和并發(fā)隊列

阻塞隊列就是在隊列基礎(chǔ)上增加了阻塞操作忘巧。簡單來說肮砾,就是在隊列為空的時候,從隊頭取數(shù)據(jù)會被阻塞袋坑。直到隊列中有了數(shù)據(jù)才能返回仗处;如果隊列已經(jīng)滿了,那么插入數(shù)據(jù)就會被阻塞枣宫,直到隊列中有空閑位置后再插入數(shù)據(jù)婆誓,然后再返回。這種基于阻塞隊列實現(xiàn)的“生產(chǎn)者 - 消費者模型”也颤,可以有效地協(xié)調(diào)生產(chǎn)和消費的速度洋幻。

線程安全的隊列我們叫作并發(fā)隊列。最簡單直接的實現(xiàn)方式是直接在 enqueue()翅娶、dequeue() 方法上加鎖文留,但是鎖粒度大并發(fā)度會比較低,同一時刻僅允許一個存或者取操作竭沫。實際上燥翅,基于數(shù)組的循環(huán)隊列,利用 CAS 原子操作蜕提,可以實現(xiàn)非常高效的并發(fā)隊列森书。這也是循環(huán)隊列比鏈?zhǔn)疥犃袘?yīng)用更加廣泛的原因。

線程池的阻塞隊列分為兩種:基于鏈表的實現(xiàn)方式谎势,可以實現(xiàn)一個支持無限排隊的無界隊列凛膏,但是可能會導(dǎo)致過多的請求排隊等待,請求處理的響應(yīng)時間過長脏榆。而基于數(shù)組實現(xiàn)的有界隊列猖毫,隊列的大小有限,所以線程池中排隊的請求超過隊列大小時须喂,接下來的請求就會被拒絕吁断,設(shè)置一個合理的隊列大小非常有講究典唇。

課后思考

還有哪些類似線程池結(jié)構(gòu)或者場景中會用到隊列的排隊請求呢?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胯府,一起剝皮案震驚了整個濱河市介衔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌骂因,老刑警劉巖炎咖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異寒波,居然都是意外死亡乘盼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門俄烁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绸栅,“玉大人,你說我怎么就攤上這事页屠〈饪瑁” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵辰企,是天一觀的道長风纠。 經(jīng)常有香客問我,道長牢贸,這世上最難降的妖魔是什么竹观? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮潜索,結(jié)果婚禮上臭增,老公的妹妹穿的比我還像新娘。我一直安慰自己竹习,他們只是感情好誊抛,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著由驹,像睡著了一般芍锚。 火紅的嫁衣襯著肌膚如雪昔园。 梳的紋絲不亂的頭發(fā)上蔓榄,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音默刚,去河邊找鬼甥郑。 笑死,一個胖子當(dāng)著我的面吹牛荤西,可吹牛的內(nèi)容都是我干的澜搅。 我是一名探鬼主播伍俘,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勉躺!你這毒婦竟也來了癌瘾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤饵溅,失蹤者是張志新(化名)和其女友劉穎妨退,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜕企,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡咬荷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了轻掩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幸乒。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖唇牧,靈堂內(nèi)的尸體忽然破棺而出罕扎,到底是詐尸還是另有隱情,我是刑警寧澤丐重,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布壳影,位于F島的核電站,受9級特大地震影響弥臼,放射性物質(zhì)發(fā)生泄漏宴咧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一径缅、第九天 我趴在偏房一處隱蔽的房頂上張望掺栅。 院中可真熱鬧,春花似錦纳猪、人聲如沸氧卧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沙绝。三九已至,卻和暖如春鼠锈,著一層夾襖步出監(jiān)牢的瞬間闪檬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工购笆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留粗悯,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓同欠,卻偏偏與公主長得像样傍,于是被迫代替她去往敵國和親横缔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容