Java自帶消息隊(duì)列Queue的使用教程詳細(xì)講解
阻塞隊(duì)列和非阻塞隊(duì)列
非阻塞隊(duì)列
- ConcurrentLinkedQueue
單向鏈表結(jié)構(gòu)的無(wú)界并發(fā)隊(duì)列, 非阻塞隊(duì)列,由CAS實(shí)現(xiàn)線程安全,內(nèi)部基于節(jié)點(diǎn)實(shí)現(xiàn)
- ConcurrentLinkedDeque
雙向鏈表結(jié)構(gòu)的無(wú)界并發(fā)隊(duì)列, 非阻塞隊(duì)列,由CAS實(shí)現(xiàn)線程安全
- PriorityQueue
內(nèi)部基于數(shù)組實(shí)現(xiàn),線程不安全的隊(duì)列
阻塞隊(duì)列
- DelayQueue
一個(gè)支持延時(shí)獲取元素的無(wú)界阻塞隊(duì)列
- LinkedTransferQueue
一個(gè)由鏈表結(jié)構(gòu)組成的無(wú)界阻塞隊(duì)列。
- ArrayBlockingQueue
有界隊(duì)列,阻塞式,初始化時(shí)必須指定隊(duì)列大小,且不可改變;,底層由數(shù)組實(shí)現(xiàn);
- SynchronousQueue
最多只能存儲(chǔ)一個(gè)元素,每一個(gè)put操作必須等待一個(gè)take操作,否則不能繼續(xù)添加元素
- PriorityBlockingQueue
一個(gè)帶優(yōu)先級(jí)的隊(duì)列,而不是先進(jìn)先出隊(duì)列。元素按優(yōu)先級(jí)順序被移除,而且它也是無(wú)界的,也就是沒(méi)有容量上限,雖然此隊(duì)列邏輯上是無(wú)界的,但是由于資源被耗盡,所以試圖執(zhí)行添加操作可能會(huì)導(dǎo)致 OutOfMemoryError 錯(cuò)誤;
以ArrayBlockingQueue為例實(shí)現(xiàn)阻塞隊(duì)列,非阻塞隊(duì)列這里就不說(shuō)了,方法都是差不多的。
拋出異常
適用場(chǎng)景極少。因?yàn)槌绦蚓褪且€(wěn)定的運(yùn)行,盡量不要拋出異常。
private static final BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3); //拋出異常 @Test public void test(){ System.out.println(blockingQueue.add("a")); System.out.println(blockingQueue.add("b")); System.out.println(blockingQueue.add("c")); System.out.println(blockingQueue.remove()); System.out.println(blockingQueue.remove()); System.out.println(blockingQueue.remove()); // System.out.println(blockingQueue.remove()); //移除隊(duì)列當(dāng)中的元素,如果有則返回移除的元素,沒(méi)有則拋出異常:java.util.NoSuchElementException。 // System.out.println(blockingQueue.element()); //獲取隊(duì)列當(dāng)中的元素,如果有則返回,沒(méi)有則拋出異常:java.util.NoSuchElementException。 // System.out.println(blockingQueue.add("d")); //當(dāng)隊(duì)列已滿時(shí),往隊(duì)列里添加元素,則會(huì)拋出異常:Queue full。 }
特殊值
新消息添加進(jìn)隊(duì)列時(shí),如果當(dāng)前隊(duì)列已滿,則會(huì)被直接拋棄,導(dǎo)致消息丟失。
private static final BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3); //特殊值 @Test public void test2(){ System.out.println(blockingQueue.offer("a")); System.out.println(blockingQueue.offer("b")); System.out.println(blockingQueue.offer("c")); System.out.println(blockingQueue.offer("d")); //往隊(duì)列里面添加元素,超出隊(duì)列長(zhǎng)度則返回false。 System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); //移除隊(duì)列里面的元素,如果有元素,則返回元素,沒(méi)有則返回null。 }
阻塞
消息處理過(guò)快會(huì)一直阻塞,這個(gè)沒(méi)什么問(wèn)題。但是如果消息處理過(guò)慢,則會(huì)消息大量積壓,導(dǎo)致cpu占用過(guò)高程序崩潰。
private static final BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3); //阻塞 @Test public void test3() throws InterruptedException { blockingQueue.put("a"); blockingQueue.put("b"); blockingQueue.put("c"); // blockingQueue.put("d"); //如果隊(duì)列已經(jīng)滿了,則一直阻塞,直到隊(duì)列有位置。 System.out.println(blockingQueue.take()); System.out.println(blockingQueue.take()); System.out.println(blockingQueue.take()); // System.out.println(blockingQueue.take()); //如果隊(duì)列沒(méi)有元素,則一直阻塞,直到隊(duì)列有元素。 }
超時(shí)
如果隊(duì)列已滿,則在指定時(shí)間之后再次嘗試往隊(duì)列里面設(shè)置元素,設(shè)置成功返回true,失敗返回false。這相比較上面的來(lái)說(shuō)會(huì)好很多,相當(dāng)于有2次機(jī)會(huì)往隊(duì)列里面設(shè)置元素。移除元素也是同理。
private static final BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3); //超時(shí) @Test public void test4() throws InterruptedException { System.out.println(blockingQueue.offer("a")); System.out.println(blockingQueue.offer("b")); System.out.println(blockingQueue.offer("c")); System.out.println(blockingQueue.offer("d",3, TimeUnit.SECONDS)); //往隊(duì)列里面添加元素,如果隊(duì)列已滿,則等待指定時(shí)間再次往隊(duì)列里面設(shè)置元素,設(shè)置成功返回true,失敗返回false。 System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS)); //移除隊(duì)列里面的元素,如果隊(duì)列里面有元素,則返回元素,沒(méi)有則等待指定時(shí)間再次移除隊(duì)列里面的元素,如果有元素則返回元素,沒(méi)有則返回null }
總結(jié)
使用隊(duì)列時(shí)應(yīng)該考慮隊(duì)列的作用是一邊積壓消息,一邊處理消息,而且要保證隊(duì)列不會(huì)造成消息大量積壓。所以我們可以讓隊(duì)列不停的進(jìn)行設(shè)置元素,然后寫(xiě)個(gè)定時(shí)任務(wù),按照指定的時(shí)間,不停的消費(fèi)隊(duì)列里面的全部元素。這個(gè)指定時(shí)間要根據(jù)業(yè)務(wù)量去設(shè)置,如果業(yè)務(wù)量太少,時(shí)間間隔可以設(shè)置的長(zhǎng)一點(diǎn)。業(yè)務(wù)量大設(shè)置的短一點(diǎn),如:1s執(zhí)行一次,一次全部取完隊(duì)列里的元素。這種情況就不建議使用固定長(zhǎng)度的消息隊(duì)列,而應(yīng)該使用自動(dòng)擴(kuò)容的消息隊(duì)列,因?yàn)槟銦o(wú)法直到消息隊(duì)列的具體長(zhǎng)度是多少。
到此這篇關(guān)于Java自帶消息隊(duì)列Queue的使用教程詳細(xì)講解的文章就介紹到這了,更多相關(guān)Java自帶消息隊(duì)列Queue內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java8使用LocalDate計(jì)算日期實(shí)例代碼解析
這篇文章主要介紹了Java8使用LocalDate計(jì)算實(shí)例代碼解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04使用SpringMVC響應(yīng)json格式返回的結(jié)果類(lèi)型
這篇文章主要介紹了使用SpringMVC響應(yīng)json格式返回的結(jié)果類(lèi)型,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Intellij Idea中進(jìn)行Mybatis逆向工程的實(shí)現(xiàn)
這篇文章主要介紹了Intellij Idea中進(jìn)行Mybatis逆向工程的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05java頁(yè)面設(shè)計(jì)之事件處理綜合介紹
java頁(yè)面設(shè)計(jì)之事件處理,當(dāng)你把界面都設(shè)計(jì)好了,總需要添加相應(yīng)的執(zhí)行動(dòng)作給組件,在JAVA中有相應(yīng)的時(shí)間處理機(jī)制,叫做監(jiān)聽(tīng)器2012-12-12Java實(shí)現(xiàn)Excel表單控件的添加與刪除
本文通過(guò)Java代碼示例介紹如何在Excel表格中添加表單控件,包括文本框、單選按鈕、復(fù)選框、組合框、微調(diào)按鈕等,以及如何刪除Excel中的指定表單控件,需要的可以參考一下2022-05-05SpringDataJPA實(shí)體類(lèi)關(guān)系映射配置方式
這篇文章主要介紹了SpringDataJPA實(shí)體類(lèi)關(guān)系映射配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12MyBatis-Plus使用ActiveRecord(AR)實(shí)現(xiàn)CRUD
本文將結(jié)合實(shí)例代碼,介紹MyBatis-Plus使用ActiveRecord(AR)實(shí)現(xiàn)CRUD,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07Springboot+Mybatis-plus不使用SQL語(yǔ)句進(jìn)行多表添加操作及問(wèn)題小結(jié)
這篇文章主要介紹了在Springboot+Mybatis-plus不使用SQL語(yǔ)句進(jìn)行多表添加操作,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04