【Java技術(shù)】盤點(diǎn) Java 中的隊(duì)列

隊(duì)列是一種重要的數(shù)據(jù)結(jié)構(gòu)沦辙,Java 語言提供了隊(duì)列的支持司浪,內(nèi)置了多種類型的隊(duì)列供我們使用消痛。限于篇幅且叁,本文不會(huì)討論太多細(xì)節(jié)。

隊(duì)列數(shù)據(jù)結(jié)構(gòu)

隊(duì)列是一個(gè)先進(jìn)先出的抽象數(shù)據(jù)結(jié)構(gòu)秩伞,可類比于生活中的排隊(duì)場(chǎng)景逞带。通常情況下,隊(duì)列有數(shù)組和鏈表兩種實(shí)現(xiàn)方式纱新。

采用鏈表實(shí)現(xiàn)的隊(duì)列展氓,沒有個(gè)數(shù)限制。插入元素時(shí)直接接在鏈表的尾部脸爱,取出元素時(shí)直接從鏈表的頭部取出即可遇汞。

采用數(shù)組實(shí)現(xiàn)的隊(duì)列,通常是循環(huán)數(shù)組,受限于數(shù)組的大小空入,存在天然的個(gè)數(shù)上限络它。插入和取出元素時(shí),必須采用隊(duì)列頭部指針和隊(duì)列尾部指針進(jìn)行隊(duì)列滿和隊(duì)列空的判斷歪赢。

Java 隊(duì)列定義

Java 定義了隊(duì)列的基本操作化戳,接口類型為?java.util.Queue,接口定義如下所示埋凯。Queue 定義了兩套隊(duì)列操作方法:

  • add点楼、remove、element 操作失敗拋出異常白对;

  • offer 操作失敗返回 false 或拋出異常掠廓,poll、peek 操作失敗返回 null躏结;


  • public interface Queue<E> extends Collection<E> {
        //插入元素却盘,成功返回true,失敗拋出異常
        boolean add(E e);
    
        //插入元素媳拴,成功返回true黄橘,失敗返回false或拋出異常 
        boolean offer(E e);
    
        //取出并移除頭部元素,空隊(duì)列拋出異常 
        E remove();
    
        //取出并移除頭部元素屈溉,空隊(duì)列返回null 
        E poll();
    
        //取出但不移除頭部元素塞关,空隊(duì)列拋出異常 
        E element();
    
        //取出但不移除頭部元素,空隊(duì)列返回null 
        E peek();
    }


    Queue 作為先進(jìn)先出隊(duì)列子巾,只能從頭部取元素帆赢、插入元素到尾部。Java 同樣定義了雙向隊(duì)列 Deque线梗,可以同時(shí)在頭部椰于、尾部插入和取出元素,接口定義如下所示仪搔。Deque 也同樣定義了兩套隊(duì)列操作方法瘾婿,針對(duì)頭部操作方法為 xxxFirst、針對(duì)尾部操作方法為 xxxLast:

  • add烤咧、remove偏陪、get 操作失敗拋出異常;

  • offer 操作失敗返回 false 或拋出異常煮嫌,poll笛谦、peek 操作失敗返回 null;

  • Deque 另外還有?removeFirstOccurrence昌阿、removeLastOccurrence 方法用于刪除指定元素饥脑,元素存在則刪除恳邀,不存在則隊(duì)列不變。


    public interface Deque<E> extends Queue<E> {
        //插入元素到隊(duì)列頭部好啰,失敗拋出異常 
        void addFirst(E e);
    
        //插入元素到隊(duì)列尾部轩娶,失敗拋出異常 ?
        void addLast(E e);
    
        //插入元素到隊(duì)列頭部儿奶,失敗返回false或拋出異常 
        boolean offerFirst(E e);
    
        //插入元素到隊(duì)列尾部框往,失敗返回false拋出異常 ?
        boolean offerLast(E e);
    
        //取出并移除頭部元素,空隊(duì)列拋出異常 
        E removeFirst();
    
        //取出并移除尾部元素闯捎,空隊(duì)列拋出異常 
        E removeLast();
    
        //取出并移除頭部元素椰弊,空隊(duì)列返回null
        E pollFirst();
    
        //取出并移除尾部元素,空隊(duì)列返回null
        E pollLast();
    
        //取出但不移除頭部元素瓤鼻,空隊(duì)列拋出異常
        E getFirst();
    
        //取出但不移除尾部元素秉版,空隊(duì)列拋出異常
        E getLast();
    
        //取出但不移除頭部元素,空隊(duì)列返回null
        E peekFirst();
    
        //取出但不移除尾部元素茬祷,空隊(duì)列返回null
        E peekLast();
    
        //移除指定頭部元素清焕,若不存在隊(duì)列不變,移除成功返回true 
        boolean removeFirstOccurrence(Object o);
    
        //移除指定尾部元素祭犯,若不存在隊(duì)列不變秸妥,移除成功返回true 
        boolean removeLastOccurrence(Object o);
    
        //單向隊(duì)列方法,參考Queue   
        //棧方法沃粗,參考棧
        //集合方法粥惧,參考集合定義   
    }


    Java 并發(fā)工具包中定義了阻塞隊(duì)列?BlockingQueue 和 BlockingDueue。阻塞隊(duì)列在前面的隊(duì)列定義基礎(chǔ)上增加了以下幾個(gè)方法最盅,來支持阻塞操作突雪。

  • take:取出并移除元素,如隊(duì)列為空則一直阻塞直到有元素涡贱;

  • put:插入元素咏删,如隊(duì)列滿則一直阻塞直到有空位可以插入元素;

  • 可超時(shí)的offer:插入元素并指定超時(shí)時(shí)間问词,如隊(duì)列滿等待指定的時(shí)間督函;

  • 可超時(shí)的poll:取出并移除元素,如隊(duì)列空等待指定的時(shí)間戏售。

  • Java 中的 Queue 實(shí)現(xiàn)

    Java 中的隊(duì)列實(shí)現(xiàn)侨核,基本上都繼承了 AbstractQueue 類。AbstractQueue 抽象隊(duì)列實(shí)現(xiàn)了 add灌灾、remove搓译、element 方法,這些方法調(diào)用 offer锋喜、poll些己、peek 方法并在失敗時(shí)拋出異常豌鸡,此外還提供了清空隊(duì)列的 clear 方法和批量插入元素的 addAll 方法。

    非阻塞隊(duì)列訪問隊(duì)列元素時(shí)可以立即返回段标,主要有優(yōu)先級(jí)隊(duì)列 PriorityQueue涯冠、并發(fā)隊(duì)列 ConcurrentLinkedQueue。

    PriorityQueue 是一個(gè)無界優(yōu)先級(jí)隊(duì)列逼庞,基于一個(gè)優(yōu)先級(jí)堆實(shí)現(xiàn)蛇更。隊(duì)列中的元素按照自然排序先后排列,或者使用創(chuàng)建時(shí)提供的 Comparator 比較先后順序赛糟。優(yōu)先級(jí)隊(duì)列需要比較順序派任,因此不能包含 null 元素。使用自然順序排序時(shí)璧南,元素必須是可以比較大小的掌逛,否則會(huì)導(dǎo)致類型轉(zhuǎn)換異常。優(yōu)先級(jí)隊(duì)列的頭部元素是隊(duì)列中按照順序最靠前的元素司倚,如有多個(gè)元素排序相等則隨機(jī)選擇一個(gè)豆混。

    ConcurrentLinkedQueue 是一個(gè)基于鏈表實(shí)現(xiàn)的線程安全的無界隊(duì)列。內(nèi)部元素按先進(jìn)先出的順序排序动知,最后插入的元素位于隊(duì)列尾部皿伺。ConcurrentLinkedQueue 不允許插入 null。當(dāng)有多個(gè)線程同時(shí)訪問隊(duì)列時(shí)拍柒,此隊(duì)列是一個(gè)比較合適的選擇心傀。

    Queue 接口的子接口 BlockingQueue 定義了阻塞隊(duì)列。阻塞隊(duì)列訪問隊(duì)列元素時(shí)拆讯,可能會(huì)一直阻塞直到操作完成脂男,比如從空隊(duì)列中取元素、向滿隊(duì)列中插入元素等种呐,主要有延時(shí)隊(duì)列宰翅、同步隊(duì)列、鏈表阻塞隊(duì)列爽室、數(shù)組阻塞隊(duì)列汁讼、優(yōu)先級(jí)阻塞隊(duì)列。

    DelayQueue 是一個(gè)無界延時(shí)隊(duì)列阔墩,元素只有在延時(shí)時(shí)間已經(jīng)過期的情況下才能被訪問嘿架。頭部元素是隊(duì)列中延時(shí)時(shí)間過期最久的元素。如果沒有元素過期則沒有頭部元素啸箫,取元素的方法會(huì)返回 null耸彪。當(dāng)元素過期時(shí),調(diào)用元素的 getDelay 方法會(huì)返回 0 或 負(fù)數(shù)忘苛。未過期的元素不能被取出蝉娜,但是統(tǒng)計(jì)隊(duì)列大小時(shí)仍然包含未過期元素唱较。

    SynchronousQueue 是一個(gè)同步隊(duì)列。同步隊(duì)列與其他阻塞隊(duì)列不太一樣召川,插入元素時(shí)會(huì)一直阻塞直到有另一個(gè)線程取元素南缓,取元素同樣會(huì)一直阻塞直到有另一個(gè)線程插入元素。同步隊(duì)列本身沒有容量的概念荧呐,也不保持元素汉形,可以理解為兩個(gè)線程交換數(shù)據(jù)的媒介,因此也不能執(zhí)行 size坛增、peek 類型的操作获雕。

    LinkedBlockingQueue 是一個(gè)基于鏈表實(shí)現(xiàn)的有界的阻塞隊(duì)列薄腻。如未指定隊(duì)列大小收捣,默認(rèn)為Integer.MAX_VALUE。內(nèi)部元素按先進(jìn)先出的順序排序庵楷,最后插入的元素位于隊(duì)列尾部罢艾。

    ArrayBlockingQueue 是一個(gè)基于數(shù)組實(shí)現(xiàn)的有界的阻塞隊(duì)列。一旦創(chuàng)建隊(duì)列的大小不會(huì)再發(fā)生變化尽纽,是一個(gè)典型的有界隊(duì)列咐蚯。內(nèi)部元素按先進(jìn)先出的順序排序,最后插入的元素位于隊(duì)列尾部弄贿。

    PriorityBlockingQueue 是一個(gè)無界優(yōu)先級(jí)阻塞隊(duì)列春锋。這個(gè)隊(duì)列與 PriorityQueue 類似,但當(dāng)隊(duì)列空或滿時(shí)會(huì)阻塞相關(guān)操作差凹。

    阻塞隊(duì)列經(jīng)常存在生產(chǎn)者等待消費(fèi)者消費(fèi)元素的情況期奔,BlockingQueue 的子接口 TransferQueue 定義了一種新隊(duì)列來支持這種情況,實(shí)現(xiàn)類為 LinkedTransferQueue危尿。TransferQueue?允許生產(chǎn)者調(diào)用 transfer 方法來等待消費(fèi)者調(diào)用 take 或 poll 消費(fèi)元素呐萌,如果有消費(fèi)者正在取元素則直接交給消費(fèi)者,否則便把元素插入隊(duì)列尾部并阻塞生產(chǎn)者當(dāng)前線程直到元素被消費(fèi)者取走谊娇。

    Java 中的 Deque 實(shí)現(xiàn)

    Deque 接口的實(shí)現(xiàn)相對(duì)較少肺孤,主要有 LinkedList、ArrayDeque济欢、ConcurrentLinkedDeque 和 LinkedBlockingDeque赠堵。

    LinkedList 就是我們常用的鏈表,實(shí)現(xiàn)了 Deque 接口法褥。LinkedList 為了提高性能茫叭,本身支持從鏈表兩端插入和取出元素,與 Deque 的要求恰好一致挖胃。

    ArrayDeque 是一個(gè)基于數(shù)組的雙向隊(duì)列杂靶,大小可變梆惯。ArrayDeque 是非線程安全的,在多線程并發(fā)時(shí)需要外部調(diào)用者自行處理并發(fā)吗垮。

    ConcurrentLinkedDeque 是一個(gè)基于鏈表實(shí)現(xiàn)的線程安全的無界雙向隊(duì)列垛吗。內(nèi)部元素按先進(jìn)先出的順序排序,最后插入的元素位于隊(duì)列尾部烁登,不允許插入 null怯屉。當(dāng)有多個(gè)線程同時(shí)訪問雙向隊(duì)列時(shí),此隊(duì)列是一個(gè)比較合適的選擇饵沧。

    Deque 接口有一個(gè)子接口 BlockingDeque 定義了阻塞雙向隊(duì)列锨络。實(shí)現(xiàn)類為 LinkedBlockingDeque,是一個(gè)基于鏈表實(shí)現(xiàn)的有界的阻塞雙向隊(duì)列狼牺。如未指定隊(duì)列大小羡儿,默認(rèn)為Integer.MAX_VALUE。內(nèi)部元素按先進(jìn)先出的順序排序是钥,最后插入的元素位于隊(duì)列尾部掠归。

    Java 中的隊(duì)列就討論到這里,歡迎留言留下您的觀點(diǎn)和看法悄泥。

    分享學(xué)習(xí)筆記和技術(shù)總結(jié)虏冻,內(nèi)容涉及 Java 技術(shù)、軟件架構(gòu)弹囚、前沿技術(shù)厨相、開源框架、數(shù)據(jù)結(jié)構(gòu)與算法鸥鹉、編程感悟等多個(gè)領(lǐng)域蛮穿,歡迎關(guān)注。本文首發(fā)于微信公眾號(hào)“后端開發(fā)那點(diǎn)事兒” 宋舷。

    ?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
    • 序言:七十年代末绪撵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子祝蝠,更是在濱河造成了極大的恐慌音诈,老刑警劉巖,帶你破解...
      沈念sama閱讀 218,755評(píng)論 6 507
    • 序言:濱河連續(xù)發(fā)生了三起死亡事件绎狭,死亡現(xiàn)場(chǎng)離奇詭異细溅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)儡嘶,發(fā)現(xiàn)死者居然都...
      沈念sama閱讀 93,305評(píng)論 3 395
    • 文/潘曉璐 我一進(jìn)店門益兄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘾带,“玉大人棒旗,你說我怎么就攤上這事∨蟊幔” “怎么了?”我有些...
      開封第一講書人閱讀 165,138評(píng)論 0 355
    • 文/不壞的土叔 我叫張陵窜骄,是天一觀的道長锦募。 經(jīng)常有香客問我,道長邻遏,這世上最難降的妖魔是什么糠亩? 我笑而不...
      開封第一講書人閱讀 58,791評(píng)論 1 295
    • 正文 為了忘掉前任,我火速辦了婚禮准验,結(jié)果婚禮上赎线,老公的妹妹穿的比我還像新娘。我一直安慰自己糊饱,他們只是感情好垂寥,可當(dāng)我...
      茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
    • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著济似,像睡著了一般矫废。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砰蠢,一...
      開封第一講書人閱讀 51,631評(píng)論 1 305
    • 那天,我揣著相機(jī)與錄音唉铜,去河邊找鬼台舱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛潭流,可吹牛的內(nèi)容都是我干的竞惋。 我是一名探鬼主播,決...
      沈念sama閱讀 40,362評(píng)論 3 418
    • 文/蒼蘭香墨 我猛地睜開眼灰嫉,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼拆宛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起讼撒,我...
      開封第一講書人閱讀 39,264評(píng)論 0 276
    • 序言:老撾萬榮一對(duì)情侶失蹤浑厚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后根盒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钳幅,經(jīng)...
      沈念sama閱讀 45,724評(píng)論 1 315
    • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
      茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
    • 正文 我和宋清朗相戀三年炎滞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了敢艰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
      茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
    • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡册赛,死狀恐怖钠导,靈堂內(nèi)的尸體忽然破棺而出震嫉,到底是詐尸還是另有隱情,我是刑警寧澤牡属,帶...
      沈念sama閱讀 35,742評(píng)論 5 346
    • 正文 年R本政府宣布责掏,位于F島的核電站,受9級(jí)特大地震影響湃望,放射性物質(zhì)發(fā)生泄漏换衬。R本人自食惡果不足惜,卻給世界環(huán)境...
      茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
    • 文/蒙蒙 一证芭、第九天 我趴在偏房一處隱蔽的房頂上張望瞳浦。 院中可真熱鬧,春花似錦废士、人聲如沸叫潦。這莊子的主人今日做“春日...
      開封第一講書人閱讀 31,944評(píng)論 0 22
    • 文/蒼蘭香墨 我抬頭看了看天上的太陽矗蕊。三九已至,卻和暖如春氢架,著一層夾襖步出監(jiān)牢的瞬間傻咖,已是汗流浹背。 一陣腳步聲響...
      開封第一講書人閱讀 33,060評(píng)論 1 270
    • 我被黑心中介騙來泰國打工岖研, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卿操,地道東北人。 一個(gè)月前我還...
      沈念sama閱讀 48,247評(píng)論 3 371
    • 正文 我出身青樓孙援,卻偏偏與公主長得像害淤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拓售,可洞房花燭夜當(dāng)晚...
      茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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