日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
帶你見(jiàn)識(shí)一下,Java中的方法爆炸!

本文轉(zhuǎn)載自微信公眾號(hào)「小姐姐味道」,作者小姐姐養(yǎng)的狗。轉(zhuǎn)載本文請(qǐng)聯(lián)系小姐姐味道公眾號(hào)。

創(chuàng)新互聯(lián)建站從2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元無(wú)棣做網(wǎng)站,已為上家服務(wù),為無(wú)棣各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:13518219792

要想了解Java的API有多變態(tài),就不得不提一下隊(duì)列這個(gè)接口,許多工作多年的人,依然是對(duì)此非常迷惑。雖然隊(duì)列是計(jì)算機(jī)算法中的一個(gè)基本結(jié)構(gòu),但它并不僅僅只有add這個(gè)方法。

讀完本文,再看到add、offer、put,不要再犯暈了!

1. 一段小代碼

猜猜下面的代碼會(huì)輸出啥?

 
 
 
  1. void run(Callable c){ 
  2.     try{ 
  3.         System.out.println(c.call()); 
  4.     }catch (Exception ex){ 
  5.         System.out.println(ex); 
  6.     } 
  7. void testSynchronousQueue(){ 
  8.     Queue q1 = new SynchronousQueue(); 
  9.     run(()-> q1.add(1)); 
  10.  
  11.     Queue q2 = new SynchronousQueue(); 
  12.     run(()-> q1.offer(1)); 
  13. 實(shí)在是讓人非常失望,兩次執(zhí)行都失敗了。

     
     
     
    1. java.lang.IllegalStateException: Queue full 
    2. false 

    第一次,使用add方法,程序拋出了異常,表示隊(duì)列滿了;第二次,程序返回了false,證明添加失敗。既然無(wú)法向隊(duì)列中添加元素,又沒(méi)有指定隊(duì)列大小的地方。那這個(gè)隊(duì)列,有什么鳥(niǎo)用!

    2. Queue的方法

    在了解這個(gè)隊(duì)列的使用之前,我們來(lái)看一下Queue接口所定義的方法。

    • add(E e) 插入一個(gè)元素到隊(duì)列的尾部。如果無(wú)法插入,則拋出異常
    • offer(E e) 插入一個(gè)元素到隊(duì)列的為
    • E remove() 從隊(duì)列頭移除一個(gè)元素,如果隊(duì)列為空,則拋出異常
    • E poll() 從隊(duì)列頭移除一個(gè)元素,如果隊(duì)列為空,則返回null
    • E element() 查看對(duì)頭元素,如果隊(duì)列為空,則拋出異常
    • E peek() 查看對(duì)頭元素,如果隊(duì)列為空,則返回null

    可以看到,對(duì)隊(duì)列的基本操作,只有三個(gè):插入新元素、查看隊(duì)頭、隊(duì)頭出對(duì)。根據(jù)是否拋出異常,又分為了兩類。3x2=6,共6個(gè)方法。

    喜歡刷題的同學(xué),常用的肯定是offer、poll、peek,這樣可以免去惱人的異常處理。平常的編碼,也推薦使用非異常的api,但Java為什么提供了兩套方法,來(lái)供我們使用呢?

    原因就是,Queue接口繼承了Collection接口,而add和remove等方法,是屬于Collection接口的,Queue不得不實(shí)現(xiàn)一套。事實(shí)上,add方法直接調(diào)用了offer方法,為什么多出這么一套api來(lái),真的是個(gè)謎。

     
     
     
    1. public boolean add(E e) { 
    2. if (offer(e)) 
    3.    return true; 
    4. else 
    5.    throw new IllegalStateException("Queue full"); 

    不拋異常,就容易被遺忘處理,確實(shí)是個(gè)比較牽強(qiáng)的原因。就憑這,能讓人在這么重要的基礎(chǔ)類庫(kù)里面,創(chuàng)造出這么多不同名稱的方法么?

    3. Put和Take

    相比較上面讓人糾結(jié)的add和offer,put和take方法就確實(shí)有用了。但put和take是不屬于Queue接口的,它的歸屬是BlockingQueue。不好意思,一不小心就跳到concurrent包了。

    put和take,意味著阻塞。如果操作不成功,它就一直在那里阻塞。想要它們能夠正常運(yùn)行下去,就需要有多個(gè)線程的配合。下面的代碼會(huì)往隊(duì)列里發(fā)送一個(gè)1,然后take方法拿出它,進(jìn)行打印。

     
     
     
    1. void testBlockingSynchronousQueue() throws InterruptedException { 
    2.     BlockingQueue q1 = new SynchronousQueue(); 
    3.     new Thread(()-> { 
    4.         try { 
    5.             q1.put(1); 
    6.         } catch (InterruptedException e) { 
    7.             e.printStackTrace(); 
    8.         } 
    9.     }).start(); 
    10.     new Thread(()-> { 
    11.         try { 
    12.             System.out.println(q1.take()); 
    13.         } catch (InterruptedException e) { 
    14.             e.printStackTrace(); 
    15.         } 
    16.     }).start(); 

    所以,我們來(lái)看一下這對(duì)方法。

    • put(E e) 插入元素,如果隊(duì)列滿了,它會(huì)一直阻塞等待
    • E take() 獲取隊(duì)頭元素,如果隊(duì)列為空則一直等待

    可以看到put和take配合起來(lái),很容易實(shí)現(xiàn)一個(gè)線程安全的生產(chǎn)者消費(fèi)者模型。相比較使用Queue的接口方法,我們只能通過(guò)死循環(huán)去檢測(cè),這樣阻塞的方式就特別節(jié)省資源。

    但是還沒(méi)完。阻塞的take和put方法,只能被interrupt,如何讓程序阻塞等待一段時(shí)間,然后恢復(fù)運(yùn)行呢?那就只有加入一個(gè)帶時(shí)間戳的阻塞方法。

    BlockingQueue選擇了offer和poll方法,而不是take和put,咱也搞不懂到底是為什么。

    • E poll(long timeout, TimeUnit unit)
    • boolean offer(E e, long timeout, TimeUnit unit) 依然是有返回值的

    4. 你以為這樣就完了?

    你以為這樣就完了?并沒(méi)有。我們需要把目光投向LinkedList,傳說(shuō)中幾行代碼實(shí)現(xiàn)LRU緩存的類。

    ArrayList是一個(gè)比較純凈的List,僅僅實(shí)現(xiàn)了List接口,但LinkedList就胃口大了一些。由于API設(shè)計(jì)者,盡最大可能想讓這個(gè)鏈表功能更強(qiáng)大一些,它繼承了Deque接口。由于Deque繼承了Queue,所以這個(gè)鏈表不僅僅是個(gè)隊(duì)列,還是個(gè)雙向隊(duì)列。

    所以,它們又多了一堆API,分別來(lái)描述到底是在隊(duì)頭還是隊(duì)尾進(jìn)行操作。

    • addFirst 操作隊(duì)頭,加入元素
    • addLast 操作隊(duì)尾,加入元素
    • offerFirst 操作隊(duì)頭,加入元素
    • offerLast 操作隊(duì)尾,加入元素
    • removeFirst 操作隊(duì)頭,刪除元素
    • removeLast 操作隊(duì)尾,刪除元素
    • pollFirst 操作隊(duì)頭,刪除元素
    • pollLast 操作隊(duì)尾,刪除元素
    • getFirst 獲取隊(duì)頭元素,類似element。TMD,這里為什么不用element?
    • getLast 獲取隊(duì)尾元素
    • peekFirst 獲取隊(duì)頭元素
    • peekLast 獲取隊(duì)尾元素

    當(dāng)然,這里還有pop和push,pop=removeFirst,push=addFirst。//建議不要用,太難記了。

    很好很好,由于有了頭和尾的概念,api的大小變成了3x2x2=12個(gè)!加上原來(lái)的那6個(gè),共18個(gè)(直接把pop和push忽略)。

    你要說(shuō),怎么沒(méi)有take和put這種阻塞的方法啊。原因就是LinkedList并不是并發(fā)的集合,你要找的功能,在LinkedBlockingDeque中,肯定會(huì)有takeFirst、takeLast、putLast、putFirst等。

    5. 隊(duì)列大小

    反過(guò)頭來(lái)再看我們剛開(kāi)始的SynchronousQueue,為什么無(wú)論向里面添加元素,還是提取元素,都會(huì)返回失敗?它的容量到底是多少?

    這是一個(gè)非常奇葩的類,它的內(nèi)部容量是0!已經(jīng)被硬編碼進(jìn)代碼里了。

     
     
     
    1. public int size() { 
    2.    return 0; 

    它僅僅建立了一個(gè)通道,一旦有生產(chǎn),消費(fèi)者就能立馬拿到它,它本身是不不存任何數(shù)據(jù)的。Executors.newCachedThreadPool()就使用了SynchronousQueue。

    常用的LinkedBlockingQueue、ArrayBlockingQueue,都是有界的。

    但這里還有一個(gè)比較奇葩的類,那就是ConcurrentLinkedQueue,從名字可以看出來(lái),它并不是一個(gè)阻塞的并發(fā)類,所以并沒(méi)有take和put等方法。另外,它是無(wú)界的,使用時(shí)要特別小心。你或許說(shuō),我每次判斷它的size()方法來(lái)看一下是否越界不就行了。

     
     
     
    1. public int size() { 
    2.     int count = 0; 
    3.     for (Node p = first(); p != null; p = succ(p)) 
    4.         if (p.item != null) 
    5.            // Collection.size() spec says to max out 
    6.            if (++count == Integer.MAX_VALUE) 
    7.                 break; 
    8.     return count; 

    如上代碼所示,這就是比較坑的地方,size方法,并不是O(1)時(shí)間級(jí)別的。xjjdog就曾在上面吃過(guò)大虧,最后還是不敢再亂用了。

    End

    從上面的描述可以看出來(lái)。對(duì)于一個(gè)隊(duì)列,有三套接口:插入、彈出、檢測(cè);根據(jù)是否拋異常,又分為兩套,一套會(huì)拋出異常,另外一套直接返回值,刷題黨自然喜歡后者了;如果再加上雙向的隊(duì)列,就需要再區(qū)分對(duì)頭隊(duì)尾;如果是阻塞隊(duì)列,還要再加上一個(gè)維度。

    所以,對(duì)于一個(gè)阻塞的雙向隊(duì)列,它的基本操作方法有:(3[基本]x2[異常與返回值]+4[阻塞加超時(shí)])x3[隊(duì)頭隊(duì)尾]=5x2x3=30個(gè)方法,這就是王者LinkedBlockingDeque。

    這樣的代碼,我反正是寫(xiě)吐了。你呢?

    作者簡(jiǎn)介:小姐姐味道 (xjjdog),一個(gè)不允許程序員走彎路的公眾號(hào)。聚焦基礎(chǔ)架構(gòu)和Linux。十年架構(gòu),日百億流量,與你探討高并發(fā)世界,給你不一樣的味道。我的個(gè)人微信xjjdog0,歡迎添加好友,進(jìn)一步交流。


    名稱欄目:帶你見(jiàn)識(shí)一下,Java中的方法爆炸!
    轉(zhuǎn)載源于:http://www.5511xx.com/article/djpjiee.html