Java阻塞佇列四組API介紹(小結)
通過前面幾篇文章的學習,我們已經知道了Java中的佇列分為阻塞佇列和非阻塞佇列以及常用的七個阻塞佇列。如下圖:
本文來源:凱哥Java(kaigejava)講解Java併發系列之阻塞佇列教程。系列文章,歡迎大家從第一篇文章開始看起。
在檢視以上七個佇列的API的時候,我們可以很明顯的看到以下四組API:
- add()/remove()/remove
- offer()/poll()/peek()
- put/take()
- offer(e,time,unit)/poll(time,unit).
分別對應的是,新增元素和移除元素以及檢查隊首元素。
這四組API各有什麼不同呢?凱哥把這四組API看作是人的一生四個階段,分別是:
少年時期,初生牛犢不怕虎,一言不合就開幹,對應的是第一組API:會拋異常的API;
青年時期,吸取各方面的知識,為人處事會圓滑,對應的是第二組API:有返回值,不丟擲異常的;
中年時期,三十而立,咬定青山不放鬆,對應的是第三組API:阻塞,一直等待;
老年時期,看透人生,順其自然,對應的是第四組API:阻塞,當到了預定的超時時間,退出。
下面我們就來詳細講解這四組API
第一組API,會丟擲異常的:一言不合就開幹
新增元素:add(e):
當佇列未滿的時候,向佇列中新增元素正常;當佇列滿的時候,再向佇列中新增元素的話,會丟擲throw new IllegalStateException("Queue full");異常。
程式碼演示及執行結果:
原始碼分析:
從原始碼中,我們可以看到,呼叫的是offer(e)方法,在下文中,我們也會講解到的。如果offer方法返回true的話,就直接返回,否則就丟擲:throw new IllegalStateException("Queue full");異常的。
刪除元素:remove()
當佇列不為空的時候,呼叫該方法,返回被移除的元素;當佇列為空的時候在呼叫該方法,會丟擲異常。
來看看原始碼:
原始碼中呼叫了poll方法,當獲取到的物件不為空的時候,返回獲取到的物件;如果為空的話,就丟擲:throw new NoSuchElementException();異常。
判斷當前佇列的隊首元素:element()
該方法是獲取隊首元素的。當佇列不為空的時候,返回佇列中當前隊首元素;如果佇列為空的時候,呼叫該方法會拋異常的。
我們來看看原始碼:
獲取隊首元素程式碼演示及執行結果如下圖:
第一組API三個方法我們都講解完了。Add/remove/element方法。最大的特點就是,佇列為空或者是佇列滿了,繼續操作佇列的話,就會丟擲異常。這個凱哥根據就像我們人的一生中少年時期一樣,初生牛犢不怕虎,遇到什麼不服的或者是不順心的就暴躁了,碰不得,一碰就爆炸。一言不合就開幹!
第二組:帶有返回值的,不會丟擲異常:為人處事會圓滑了
第二組api的不像第一組那麼暴躁如雷了,不想就拋異常。第二組,不會丟擲異常了。我們接著來看看:
新增元素:offer(e)
需要主要:這裡的offer方法只有一個引數,這個和我們後面講解的一組的區別
當佇列未滿的時候,向佇列中新增元素,返回true;當佇列已經滿了,繼續向佇列中新增元素的話,不會丟擲異常,會返回false.
原始碼分析:
從原始碼中,我們可以看到,offer(e)的方法中,有個count計數器,每次新增元素後,都會count++。當count的值等於佇列的長度的時候,返回false.而不是丟擲異常。我們來用程式碼演示.
Offer(e)新增元素程式碼演示及執行結果:
刪除元素:poll()
注意:引數為空哦!
當佇列不為空的時候,返回被移除的元素,當佇列為空的時候,返回null.而不是丟擲異常。
原始碼分析:
從原始碼中,我們將看到count這個計數器又起作用了。先判斷count是否==0
如果不等於0,呼叫dequeue方法,count--,然後將獲取到的元素返回;
如果count == 0的話,直接返回null.
原始碼如下圖:
程式碼演示及執行結果:
獲取隊首元素:peek()
當佇列不為空的時候,返回當前佇列的隊首元素;如果佇列為空的時候,返回null,而不是丟擲異常。
原始碼分析:
在原始碼中,我們可以看到呼叫了itemAt(takeIndex)方法。但是在這個方法後面有這麼已經註釋:null when queue is empty。原始碼如下圖:
程式碼演示:
從執行的結果,我們可以看到,當移除最後一個元素:kaigejava的時候,獲取到的隊首元素已經為null了。因為佇列為空了,所以,就算後面還有迴圈,獲取到的隊首元素依然是null,而不是丟擲異常。執行結果如下圖:
從第二組API中,我們可以看到,不像第一組那麼極端了。當佇列為空或者是佇列滿的時候,返回資料告知物件。這個就像我們人生由少年時代,進入了青年時代,經過學校的洗禮之後,為人處事學會了圓滑了。
接下來,我們就該進入人生第三個階段:中年時代,我們一起來看看這個階段的api又是什麼樣子的
第三組:阻塞,一直等待:三十而立,咬定青山不放鬆
第三組API,相對於第一組和第二組最大的區別就是:第三組會等待著,如果不被中斷,就會等到天荒地老。
新增元素:put(e)
當佇列滿的時候,進入阻塞等待狀態,一直等待,直到可以新增到佇列中為止。
需要說明:在阻塞等待過程中,有可能會被中斷,所以會丟擲中斷異常:throws InterruptedException。
我們先來看看原始碼:
在原始碼中,我們會看到while迴圈來判斷count的值是否等於佇列的長度,如果不等於,就enqueue.然後count++;如果count的值等於佇列的長度的是,就呼叫notFull.await()方法,而notfull是condition物件。在之前的文章學習中,我們知道coditon.await()方法會進入阻塞狀態。原始碼如下圖:
程式碼演示及執行結果:
我們可以看到,當新增第四個元素的時候,佇列進入了阻塞狀態。如下圖:
刪除元素:take()
當佇列不為空的時候,返回被移除的元素;當佇列為空的時候,進入阻塞等待狀態。
原始碼分析:
程式碼演示:
這一組佇列,就像進入中年時期的我們一樣,三十而立,要好好工作,努力工作。只要天不塌,地不陷,一直工作著。
第四組:帶有等待超時的阻塞API
如果第三組API一直阻塞等待著,你受不了的話,併發大師還為我們準備了第四組API,帶有超時時間的
新增元素:offer(e,unit)
引數說明:
e:將要被新增到佇列中的元素
time:long型別的。預設定的需要等待的時間
unit:TimeUnit.超時時間的單位
來看看原始碼:
從原始碼中我們將會看到:
判斷count的值是否等於佇列的長度
如果不等於,呼叫enqueue方法,然後count++,返回true.
如果count==佇列的長度的時候,判斷設定的等待超時時間是否小於等於0
如果等待的時間大於0的話,進入notFull.awaitNanos方法中進行阻塞等待。
在前面文章中,我們詳細講解過condition.awaitNanos這個方法。這裡就不再贅述了。
當等待的時間小於等於0的時候,就返回false.
原始碼如下圖:
程式碼演示:
刪除元素:poll(time,unit)
當佇列為空的時候,進入阻塞等待,等到超時時間的時候,返回null.退出等待。
程式碼演示:
第四組API帶有等待超時時間,就像是我們人的一生老年時期,看透一切了。一切都是順其自然了,不再爭強好勝了。
總結:
凱哥通過人的一生四個階段來比喻這四組API是為了讓大家更好記憶。接下來,我們來進行總結:
到此這篇關於Java阻塞佇列四組API介紹(小結)的文章就介紹到這了,更多相關Java阻塞佇列內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!