乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Stack有性能問題?推薦用ArrayDeque隊列!隊列是什么?什么是雙端隊列、延遲系列、阻塞隊列,全是知識盲區(qū)!

       小傅哥 2021-12-13

      作者:小傅哥
      博客:https://

      ?

      沉淀、分享、成長,讓自己和他人都能有所收獲!??

      ?

      目錄

      • 一、前言

      • 二、面試題

      • 三、數(shù)據(jù)結(jié)構(gòu)

      • 四、源碼學習

        • 1. 先說一個被拋棄Stack

        • 2. 雙端隊列ArrayDeque

        • 3. 雙端隊列LinkedList

        • 4. 延時隊列DelayQueue

        • 5. 還有哪些隊列?

      • 五、總結(jié)

      一、前言

      買房子最重要的是房屋格局!

      如果買房子能接受地理位置、平米價格外,最重要的就是房屋格局。什么?丈母娘!你?????♂,出去! 房屋的格局其實對應的就是程序開發(fā)的根本,也就是數(shù)據(jù)結(jié)構(gòu)。有的土豪可以用錢換空間,房間格局更大,那沒錢的就只能選經(jīng)濟小空間節(jié)省錢。是不是很像不同的數(shù)據(jù)結(jié)構(gòu),直接影響著是空間換時間,還是時間換空間。那么,再細看房間,如;客廳沙發(fā)坐人像散列表、上衛(wèi)生間像進棧、廚房不大先進后出像隊列、晚上各回各屋子像進數(shù)組。所以你能在這個屋子生活的舒服,很大一部分取決于整個房間的布局。也同樣你能把程序?qū)懞?,很大的原因是因為?shù)據(jù)結(jié)構(gòu)定義的合理。

      那么決定這程序開發(fā)基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)有哪些呢?

      程序開發(fā)中數(shù)據(jù)結(jié)構(gòu)可以分為這八類;數(shù)組鏈表、、隊列、散列表、、、。其中,數(shù)組、鏈表、散列表、樹是程序開發(fā)直接或者間接用到的最多的。相關(guān)的對應實現(xiàn)類可以包括如下;

      類型實現(xiàn)文章
      數(shù)組ArrayListArrayList也這么多知識?一個指定位置插入就把謝飛機面暈了!
      鏈表LinkedListLinkedList插入速度比ArrayList快?你確定嗎?
      2-3樹、紅黑樹看圖說話,講解2-3平衡樹「紅黑樹的前身」
      紅黑樹操作原理,解析什么時候染色、怎么進行旋轉(zhuǎn)、與2-3樹有什么關(guān)聯(lián)
      散列表HashMapHashMap核心知識,擾動函數(shù)、負載因子、擴容鏈表拆分,深度學習
      HashMap數(shù)據(jù)插入、查找、刪除、遍歷,源碼分析
      Stack
      隊列Queue、Deque
      • 如上,除了棧和隊列外,小傅哥已經(jīng)編寫了非常細致的文章來介紹了其他數(shù)據(jù)結(jié)構(gòu)的核心知識和具體的實現(xiàn)應用。
      • 接下來就把剩下的棧和隊列在本章介紹完,其實這部分知識并不難了,有了以上對數(shù)組和鏈表的理解,其他的數(shù)據(jù)結(jié)構(gòu)基本都從這兩方面擴展出來的。

      本文涉及了較多的代碼和實踐驗證圖稿,歡迎關(guān)注公眾號:bugstack蟲洞棧,回復下載得到一個鏈接打開后,找到ID:19??獲?。?/span>

      二、面試題

      謝飛機,飛機你旁邊這是?

      「答」:啊,謝坦克,我弟弟。還沒畢業(yè),想來看看大公司面試官的容顏。

      「問」:飛機,上次把LinkedList都看了吧,那我問你哈。LinkedList可以當隊列用嗎?

      「答」:?。靠梢?,可以吧!

      「問」:那,數(shù)組能當隊列用嗎?不能?對列有啥特點嗎?

      「答」:隊列先進先出,嗯,嗯。

      「問」:還有嗎?了解延時隊列嗎?雙端隊列呢?

      飛機拉著坦克的手出門了,還帶走了面試官送的一本《面經(jīng)手冊》,坦克對飛機說,基礎(chǔ)不牢,地動山搖,我要好好學習。

      三、數(shù)據(jù)結(jié)構(gòu)

      把我們已經(jīng)掌握了的數(shù)組和鏈表立起來,就是棧和隊列了!

      如圖,這一章節(jié)的數(shù)據(jù)結(jié)構(gòu)的知識點并不難,只要已經(jīng)學習過數(shù)組和鏈表,那么對于掌握其他數(shù)據(jù)結(jié)構(gòu)就已經(jīng)有了基礎(chǔ),只不過對于數(shù)據(jù)的存放、讀取加了一些限定規(guī)則。尤其像鏈表這樣的數(shù)據(jù)結(jié)構(gòu),只操作頭尾的效率是非常高的。

      四、源碼學習

      1. 先說一個被拋棄Stack

      有時候不會反而不會犯錯誤!怕就怕在只知道一知半解。

      拋棄的不是棧這種數(shù)據(jù)結(jié)構(gòu),而是Stack實現(xiàn)類,如果你還不了解就用到業(yè)務開發(fā)中,就很可能會影響系統(tǒng)性能。其實Stack這個棧已經(jīng)是不建議使用了,但是為什么不建議使用,我們可以通過使用和源碼分析了解下根本原因。

      在學習之前先大概的了解下這樣的數(shù)據(jù)結(jié)構(gòu),它很像羽毛球的擺放,是一種后進先出隊列,如下;

      1.1 功能使用

      @Test
      public void test_stack() {
          Stack<String> s = new Stack<String>();
          s.push("aaa");
          s.push("bbb");
          s.push("ccc");
          
          System.out.println("獲取最后一個元素:" + s.peek());
          System.out.println("獲取最后一個元素:" + s.lastElement());
          System.out.println("獲取最先放置元素:" + s.firstElement());
          
          System.out.println("彈出一個元素[LIFO]:" + s.pop());
          System.out.println("彈出一個元素[LIFO]:" + s.pop());
          System.out.println("彈出一個元素[LIFO]:" + s.pop());
      }

      例子是對Stack棧的使用,如果不運行你能知道它的輸出結(jié)果嗎?

      「測試結(jié)果:」

      獲取最后一個元素:ccc
      獲取最后一個元素:ccc
      獲取最先放置元素:aaa
      彈出一個元素[LIFO]:ccc
      彈出一個元素[LIFO]:bbb
      彈出一個元素[LIFO]:aaa

      Process finished with exit code 0

      看到測試結(jié)果,與你想的答案是否一致?

      • peek,是偷看的意思,就是看一下,不會彈出元素。滿足后進先出的規(guī)則,它看的是最后放進去的元素ccc。
      • lastElement、firstElement,字面意思的方法,獲取最后一個和獲取第一個元素。
      • pop,是隊列中彈出元素,彈出后也代表著要把屬于這個位置都元素清空,刪掉。

      1.2 源碼分析

      我們說Stack棧,這個實現(xiàn)類已經(jīng)不推薦使用了,需要從它的源碼上看。

      /**
       *
       * <p>A more complete and consistent set of LIFO stack operations is
       * provided by the {@link Deque} interface and its implementations, which
       * should be used in preference to this class.  For example:
       * <pre>   {@code
       *   Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
       *   
       * @author  Jonathan Payne
       * @since   JDK1.0
       */

      public class Stack<Eextends Vector<E
      s.push("aaa");

      public synchronized void addElement(E obj) {
          modCount++;
          ensureCapacityHelper(elementCount + 1);
          elementData[elementCount++] = obj;
      }
      1. Stack 棧是在JDK1.0時代時,基于繼承Vector,實現(xiàn)的。本身Vector就是一個不推薦使用的類,主要在于它的一些操作方法鎖??(synchronized)的力度太粗,都是放到方法上。
      2. Stack 棧底層是使用Vector數(shù)組實現(xiàn),在學習ArrayList時候我們知道,數(shù)組結(jié)構(gòu)在元素添加和擅長需要通過System.arraycopy,進行擴容操作。而本身棧的特點是首尾元素的操作,也不需要遍歷,使用數(shù)組結(jié)構(gòu)其實并不太理想。
      3. 同時在這個方法的注釋上也明確標出來,推薦使用Deque<Integer> stack = new ArrayDeque<Integer>();,雖然這也是數(shù)組結(jié)構(gòu),但是它沒有粗粒度的鎖,同時可以申請指定空間并且在擴容時操作時也要優(yōu)于Stack 。并且它還是一個雙端隊列,使用起來更靈活。

      2. 雙端隊列ArrayDeque

      ArrayDeque 是基于數(shù)組實現(xiàn)的可動態(tài)擴容的雙端隊列,也就是說你可以在隊列的頭和尾同時插入和彈出元素。當元素數(shù)量超過數(shù)組初始化長度時,則需要擴容和遷移數(shù)據(jù)。

      「數(shù)據(jù)結(jié)構(gòu)和操作」,如下;

      小傅哥 & 雙端隊列數(shù)據(jù)結(jié)構(gòu)操作

      從上圖我們可以了解到如下幾個知識點;

      1. 雙端隊列是基于數(shù)組實現(xiàn),所以擴容遷移數(shù)據(jù)操作。
      2. push,像結(jié)尾插入、offerLast,向頭部插入,這樣兩端都滿足后進先出。
      3. 整體來看,雙端隊列,就是一個環(huán)形。所以擴容后繼續(xù)插入元素也滿足后進先出。

      2.1 功能使用

      @Test
      public void test_ArrayDeque() {
          Deque<String> deque = new ArrayDeque<String>(1);
          
          deque.push("a");
          deque.push("b");
          deque.push("c");
          deque.push("d");
          
          deque.offerLast("e");
          deque.offerLast("f");
          deque.offerLast("g");
          deque.offerLast("h");  // 這時候擴容了
          
          deque.push("i");
          deque.offerLast("j");
          
          System.out.println("數(shù)據(jù)出棧:");
          while (!deque.isEmpty()) {
              System.out.print(deque.pop() + " ");
          }
      }

      以上這部分代碼就是與上圖的展現(xiàn)是一致的,按照圖中的分析我們看下輸出結(jié)果,如下;

      數(shù)據(jù)出棧:
      i d c b a e f g h j 
      Process finished with exit code 0
      • i d c b a e f g h j,正好滿足了我們的說的數(shù)據(jù)出棧順序。可以參考上圖再進行理解

      2.2 源碼分析

      ArrayDeque 這種雙端隊列是基于數(shù)組實現(xiàn)的,所以源碼上從初始化到數(shù)據(jù)入棧擴容,都會有數(shù)組操作的痕跡。接下來我們就依次分析下。

      2.2.1 初始化

      new ArrayDeque<String>(1);,其實它的構(gòu)造函數(shù)初始化默認也提供了幾個方法,比如你可以指定大小以及提供默認元素。

      private static int calculateSize(int numElements) {
          int initialCapacity = MIN_INITIAL_CAPACITY;
          // Find the best power of two to hold elements.
          // Tests "<=" because arrays aren't kept full.
          if (numElements >= initialCapacity) {
              initialCapacity = numElements;
              initialCapacity |= (initialCapacity >>>  1);
              initialCapacity |= (initialCapacity >>>  2);
              initialCapacity |= (initialCapacity >>>  4);
              initialCapacity |= (initialCapacity >>>  8);
              initialCapacity |= (initialCapacity >>> 16);
              initialCapacity++;
              if (initialCapacity < 0)   // Too many elements, must back off
                  initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 element
          }
          return initialCapacity;
      }
      • 在初始化的過程中,它需要找到你當前傳輸值最小的2的倍數(shù)的一個容量。這與HashMap的初始化過程相似。
      2.2.2 數(shù)據(jù)入棧

      deque.push("a");,ArrayDeque,提供了一個 push 方法,這個方法與deque.offerFirst(“a”),一致,因為它們的底層源碼是一樣的,如下;

      「addFirst:」

      public void addFirst(E e) {
          if (e == null)
              throw new NullPointerException();
          elements[head = (head - 1) & (elements.length - 1)] = e;
          if (head == tail)
              doubleCapacity();
      }

      「addLast:」

      public void addLast(E e) {
          if (e == null)
              throw new NullPointerException();
          elements[tail] = e;
          if ( (tail = (tail + 1) & (elements.length - 1)) == head)
              doubleCapacity();
      }

      這部分入棧元素,其實就是給數(shù)組賦值,知識點如下;

      1. addFirst()中,定位下標,head = (head - 1) & (elements.length - 1),因為我們的數(shù)組長度是2^n的倍數(shù),所以 2^n - 1 就是一個全是1的二進制數(shù),可以用于與運算得出數(shù)組下標。
      2. 同樣addLast()中,也使用了相同的方式定位下標,只不過它是從0開始,往上增加。
      3. 最后,當頭(head)與尾(tile),數(shù)組則需要兩倍擴容doubleCapacity。

      下標計算:head = (head - 1) & (elements.length - 1)

      • (0 - 1) & (8 - 1) = 7
      • (7 - 1) & (8 - 1) = 6
      • (6 - 1) & (8 - 1) = 5
      • ...
      2.2.3 兩倍擴容,數(shù)據(jù)遷移
      private void doubleCapacity() {
          assert head == tail;
          int p = head;
          int n = elements.length;
          int r = n - p; // number of elements to the right of p
          int newCapacity = n << 1;
          if (newCapacity < 0)
              throw new IllegalStateException("Sorry, deque too big");
          Object[] a = new Object[newCapacity];
          System.arraycopy(elements, p, a, 0, r);
          System.arraycopy(elements, 0, a, r, p);
          elements = a;
          head = 0;
          tail = n;
      }

      其實以上這部分源碼,就是進行兩倍n << 1擴容,同時把兩端數(shù)據(jù)遷移進新的數(shù)組,整個操作過程也與我們上圖對應。為了更好的理解,我們單獨把這部分代碼做一些測試。

      「測試代碼:」

      @Test
      public void test_arraycopy() {
          int head = 0, tail = 0;
          Object[] elements = new Object[8];
          elements[head = (head - 1) & (elements.length - 1)] = "a";
          elements[head = (head - 1) & (elements.length - 1)] = "b";
          elements[head = (head - 1) & (elements.length - 1)] = "c";
          elements[head = (head - 1) & (elements.length - 1)] = "d";
          
          elements[tail] = "e";
          tail = (tail + 1) & (elements.length - 1);
          elements[tail] = "f";
          tail = (tail + 1) & (elements.length - 1);
          elements[tail] = "g";
          tail = (tail + 1) & (elements.length - 1);
          elements[tail] = "h";
          tail = (tail + 1) & (elements.length - 1);
          
          System.out.println("head:" + head);
          System.out.println("tail:" + tail);
          
          int p = head;
          int n = elements.length;
          int r = n - p; // number of elements to the right of p
          
          // 輸出當前的元素
          System.out.println(JSON.toJSONString(elements));
          
          // head == tail 擴容
          Object[] a = new Object[8 << 1];
          System.arraycopy(elements, p, a, 0, r);
          System.out.println(JSON.toJSONString(a));
          System.arraycopy(elements, 0, a, r, p);
          System.out.println(JSON.toJSONString(a));
          
          elements = a;
          head = 0;
          tail = n;
          a[head = (head - 1) & (a.length - 1)] = "i";
          System.out.println(JSON.toJSONString(a));
      }

      以上的測試過程主要模擬了8個長度的空間的數(shù)組,在進行雙端隊列操作時數(shù)組擴容,數(shù)據(jù)遷移操作,可以單獨運行,測試結(jié)果如下;

      head:4
      tail:4
      ["e","f","g","h","d","c","b","a"]
      ["d","c","b","a",null,null,null,null,null,null,null,null,null,null,null,null]
      ["d","c","b","a","e","f","g","h",null,null,null,null,null,null,null,null]
      ["d","c","b","a","e","f","g","h","j",null,null,null,null,null,null,"i"]

      Process finished with exit code 0

      從測試結(jié)果可以看到;

      1. 當head與tail相等時,進行擴容操作。
      2. 第一次數(shù)據(jù)遷移,System.arraycopy(elements, p, a, 0, r);,「d、c、b、a」,落入新數(shù)組。
      3. 第二次數(shù)據(jù)遷移,System.arraycopy(elements, 0, a, r, p);,「e、f、g、h」,落入新數(shù)組。
      4. 最后再嘗試添加新的元素,i和j。每一次的輸出結(jié)果都可以看到整個雙端鏈路的變化。

      3. 雙端隊列LinkedList

      Linkedlist天生就可以支持雙端隊列,而且從頭尾取數(shù)據(jù)也是它時間復雜度O(1)的。同時數(shù)據(jù)的插入和刪除也不需要像數(shù)組隊列那樣拷貝數(shù)據(jù),雖然Linkedlist有這些優(yōu)點,但不能說ArrayDeque因為有數(shù)組復制性能比它低。

      「Linkedlist,數(shù)據(jù)結(jié)構(gòu)」

      3.1 功能使用

      @Test
      public void test_Deque_LinkedList(){
          Deque<String> deque = new LinkedList<>();
          deque.push("a");
          deque.push("b");
          deque.push("c");
          deque.push("d");
          deque.offerLast("e");
          deque.offerLast("f");
          deque.offerLast("g");
          deque.offerLast("h"); 
          deque.push("i");
          deque.offerLast("j");
          
          System.out.println("數(shù)據(jù)出棧:");
          while (!deque.isEmpty()) {
              System.out.print(deque.pop() + " ");
          }
      }

      「測試結(jié)果」

      數(shù)據(jù)出棧:
      i d c b a e f g h j 

      Process finished with exit code 0
      • 測試結(jié)果上看與使用ArrayDeque是一樣的,功能上沒有差異。

      3.2 源碼分析

      「壓?!?/strong>:deque.push("a");、deque.offerFirst("a");

      private void linkFirst(E e) {
          final Node<E> f = first;
          final Node<E> newNode = new Node<>(null, e, f);
          first = newNode;
          if (f == null)
              last = newNode;
          else
              f.prev = newNode;
          size++;
          modCount++;
      }

      「壓棧」deque.offerLast("e");

      void linkLast(E e) {
          final Node<E> l = last;
          final Node<E> newNode = new Node<>(l, e, null);
          last = newNode;
          if (l == null)
              first = newNode;
          else
              l.next = newNode;
          size++;
          modCount++;
      }
      • linkFirst、linkLast,兩個方法分別是給鏈表的首尾節(jié)點插入元素,因為這是鏈表結(jié)構(gòu),所以也不存在擴容,只需要把雙向鏈路鏈接上即可。

      4. 延時隊列DelayQueue

      你是否有時候需要把一些數(shù)據(jù)存起來,倒計時到某個時刻在使用?

      在Java的隊列數(shù)據(jù)結(jié)構(gòu)中,還有一種隊列是延時隊列,可以通過設(shè)定存放時間,依次輪訓獲取。

      4.1 功能使用

      「先寫一個Delayed的實現(xiàn)類」

      public class TestDelayed implements Delayed {

          private String str;
          private long time;

          public TestDelayed(String str, long time, TimeUnit unit) {
              this.str = str;
              this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);
          }

          @Override
          public long getDelay(TimeUnit unit) {
              return time - System.currentTimeMillis();
          }

          @Override
          public int compareTo(Delayed o) {
              TestDelayed work = (TestDelayed) o;
              long diff = this.time - work.time;
              if (diff <= 0) {
                  return -1;
              } else {
                  return 1;
              }
          }

          public String getStr() {
              return str;
          }
      }
      • 這個相當于延時隊列的一個固定模版方法,通過這種方式來控制延時。

      「案例測試」

      @Test
      public void test_DelayQueue() throws InterruptedException {
          DelayQueue<TestDelayed> delayQueue = new DelayQueue<TestDelayed>();
          delayQueue.offer(new TestDelayed("aaa"5, TimeUnit.SECONDS));
          delayQueue.offer(new TestDelayed("ccc"1, TimeUnit.SECONDS));
          delayQueue.offer(new TestDelayed("bbb"3, TimeUnit.SECONDS));
          
          logger.info(((TestDelayed) delayQueue.take()).getStr());
          logger.info(((TestDelayed) delayQueue.take()).getStr());
          logger.info(((TestDelayed) delayQueue.take()).getStr());
      }

      「測試結(jié)果」

      01:44:21.000 [main] INFO  org.itstack.interview.test.ApiTest - ccc
      01:44:22.997 [main] INFO  org.itstack.interview.test.ApiTest - bbb
      01:44:24.997 [main] INFO  org.itstack.interview.test.ApiTest - aaa

      Process finished with exit code 0
      • 在案例測試中我們分別設(shè)定不同的休眠時間,1、3、5,TimeUnit.SECONDS。
      • 測試結(jié)果分別在21、22、24,輸出了我們要的隊列結(jié)果。
      • 隊列中的元素不會因為存放的先后順序而導致輸出順序,它們是依賴于休眠時長決定。

      4.2 源碼分析

      4.2.1 元素入棧

      「入棧:」delayQueue.offer(new TestDelayed("aaa", 5, TimeUnit.SECONDS));

      public boolean offer(E e) {
          if (e == null)
              throw new NullPointerException();
          modCount++;
          int i = size;
          if (i >= queue.length)
              grow(i + 1);
          size = i + 1;
          if (i == 0)
              queue[0] = e;
          else
              siftUp(i, e);
          return true;
      }

      private void siftUpUsingComparator(int k, E x) {
          while (k > 0) {
              int parent = (k - 1) >>> 1;
              Object e = queue[parent];
              if (comparator.compare(x, (E) e) >= 0)
                  break;
              queue[k] = e;
              k = parent;
          }
          queue[k] = x;
      }
      • 關(guān)于數(shù)據(jù)存放還有 ReentrantLock 可重入鎖??,但暫時不是我們本章節(jié)數(shù)據(jù)結(jié)構(gòu)的重點,后面章節(jié)會介紹到。
      • DelayQueue 是基于數(shù)組實現(xiàn)的,所以可以動態(tài)擴容,另外它插入元素的順序并不影響最終的輸出順序。
      • 而元素的排序依賴于compareTo方法進行排序,也就是休眠的時間長短決定的。
      • 同時只有實現(xiàn)了Delayed接口,才能存放元素。
      4.2.2 元素出棧

      「出?!?/strong>:delayQueue.take()

      public E take() throws InterruptedException {
          final ReentrantLock lock = this.lock;
          lock.lockInterruptibly();
          try {
              for (;;) {
                  E first = q.peek();
                  if (first == null)
                      available.await();
                  else {
                      long delay = first.getDelay(NANOSECONDS
                      if (delay <= 0)
                          return q.poll()
      ;
                      first = null// don't retain ref while
                      if (leader != null)
                          available.await();
                      else {
                          Thread thisThread = Thread.currentT
                          leader = thisThread;
                          try {
                              available.awaitNanos(delay);
                          } finally {
                              if (leader == thisThread)
                                  leader = null;
                          }
                      }
                  }
              }
          } finally {
              if (leader == null && q.peek() != null)
                  available.signal();
              lock.unlock();
          }
      }
      • 這部分的代碼有點長,主要是元素的獲取。DelayQueueLeader-Followr 模式的變種,消費者線程處于等待await時,總是等待最先休眠完成的元素。
      • 這里會最小化的空等時間,提高線程利用率。數(shù)據(jù)結(jié)構(gòu)講完后,后面會有專門章節(jié)介紹

      5. 還有哪些隊列?

      5.1 隊列類結(jié)構(gòu)

      類型實現(xiàn)描述
      QueueLinkedBlockingQueue由鏈表結(jié)構(gòu)組成的有界阻塞隊列
      QueueArrayBlockingQueue由數(shù)組結(jié)構(gòu)組成的有界阻塞隊列
      QueuePriorityBlockingQueue支持優(yōu)先級排序的無界阻塞隊列
      QueueSynchronousQueue不存儲元素的阻塞隊列
      QueueLinkedTransferQueue由鏈表結(jié)構(gòu)組成的無界阻塞隊列
      DequeLinkedBlockingDeque由鏈表結(jié)構(gòu)組成的雙向阻塞隊列
      DequeConcurrentLinkedDeque由鏈表結(jié)構(gòu)組成的線程安全的雙向阻塞隊列
      • 除了我們已經(jīng)講過的隊列以外,剩余的基本都是阻塞隊列,也就是上面這些。
      • 在數(shù)據(jù)結(jié)構(gòu)方面基本沒有差異,只不過添加了相應的阻塞功能和鎖的機制。

      5.2 使用案例

      public class DataQueueStack {

       private BlockingQueue<DataBean> dataQueue = null;
       
       public DataQueueStack(){
        //實例化隊列
        dataQueue = new LinkedBlockingQueue<DataBean>(100);
       }
       
       /**
        * 添加數(shù)據(jù)到隊列
        * @param dataBean
        * @return
        */

       public boolean doOfferData(DataBean dataBean){
        try {
         return dataQueue.offer(dataBean, 2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
         e.printStackTrace();
         return false;
        }
       }
       
       /**
        * 彈出隊列數(shù)據(jù)
        * @return
        */

       public DataBean doPollData(){
        try {
         return dataQueue.poll(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
         e.printStackTrace();
         return null;
        }
       }
       
       /**
        * 獲得隊列數(shù)據(jù)個數(shù)
        * @return
        */

       public int doGetQueueCount(){
        return dataQueue.size();
       }
       
      }
      • 這是一個LinkedBlockingQueue隊列使用案例,一方面存儲數(shù)據(jù),一方面從隊列中獲取進行消費。
      • 因為這是一個阻塞隊列,所以在獲取元素的時候,如果隊列為空,會進行阻塞。
      • LinkedBlockingQueue是一個阻塞隊列,內(nèi)部由兩個ReentrantLock來實現(xiàn)出入隊列的線程安全,由各自的Condition對象的await和signal來實現(xiàn)等待和喚醒功能。

      五、總結(jié)

      • 關(guān)于棧和隊列的數(shù)據(jù)結(jié)構(gòu)方面到這里就介紹完了,另外這里還有一些關(guān)于阻塞隊列鎖??的應用過程,到我們后面講鎖相關(guān)知識點,再重點介紹。
      • 隊列結(jié)構(gòu)的設(shè)計非常適合某些需要LIFO或者FIFO的應用場景,同時在隊列的數(shù)據(jù)結(jié)構(gòu)中也有雙端、延時和組合的功能類,使用起來也非常方便。
      • 數(shù)據(jù)結(jié)構(gòu)方面的知識到本章節(jié)算是告一段落,如果有優(yōu)秀的內(nèi)容,后面還會繼續(xù)補充。再下一章節(jié)小傅哥()準備給大家介紹,關(guān)于數(shù)據(jù)結(jié)構(gòu)中涉及的算法部分,這些主要來自于Collections類的實現(xiàn)部分。

      bugstack蟲洞棧

      沉淀、分享、成長,讓自己和他人都能有所收獲!

        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多