隊列--queue詳解


Queue: 基本上,一個隊列就是一個先入先出(FIFO)的數據結構

Queue接口與List、Set同一級別,都是繼承了Collection接口。LinkedList實現了Deque接 口。

Queue的實現


1、沒有實現的阻塞接口的LinkedList: 實現了java.util.Queue接口和java.util.AbstractQueue接口
  內置的不阻塞隊列: PriorityQueue 和 ConcurrentLinkedQueue
  PriorityQueue 和 ConcurrentLinkedQueue 類在 Collection Framework 中加入兩個具體集合實現。 
  PriorityQueue 類實質上維護了一個有序列表。加入到 Queue 中的元素根據它們的天然排序(通過其 java.util.Comparable 實現)或者根據傳遞給構造函數的 java.util.Comparator 實現來定位。
  ConcurrentLinkedQueue 是基於鏈接節點的、線程安全的隊列。並發訪問不需要同步。因為它在隊列的尾部添加元素並從頭部刪除它們,所以只要不需要知道隊列的大 小,ConcurrentLinkedQueue 對公共集合的共享訪問就可以工作得很好。收集關於隊列大小的信息會很慢,需要遍歷隊列。


2、實現阻塞接口的:
  java.util.concurrent 中加入了 BlockingQueue 接口和五個阻塞隊列類。它實質上就是一種帶有一點扭曲的 FIFO 數據結構。不是立即從隊列中添加或者刪除元素,線程執行操作阻塞,直到有空間或者元素可用。
  五個隊列所提供的各有不同:

  •  ArrayBlockingQueue :  一個由數組支持的有界隊列。
  • LinkedBlockingQueue :  一個由鏈接節點支持的可選有界隊列。
  • PriorityBlockingQueue :一個由優先級堆支持的無界優先級隊列。
  • DelayQueue :           一個由優先級堆支持的、基於時間的調度隊列。
  • SynchronousQueue :     一個利用 BlockingQueue 接口的簡單聚集(rendezvous)機制。

3、主要方法:

    add        增加一個元索                     如果隊列已滿,則拋出一個IIIegaISlabEepeplian異常
  remove     移除並返回隊列頭部的元素         如果隊列為空,則拋出一個NoSuchElementException異常
  element    返回隊列頭部的元素               如果隊列為空,則拋出一個NoSuchElementException異常
  offer      添加一個元素並返回true           如果隊列已滿,則返回false
  poll       移除並返問隊列頭部的元素         如果隊列為空,則返回null
  peek       返回隊列頭部的元素               如果隊列為空,則返回null
  put        添加一個元素                     如果隊列滿,則阻塞
  take       移除並返回隊列頭部的元素         如果隊列為空,則阻塞

4、四種隊列詳解

  (1)LinkedBlockingQueue的容量是沒有上限的(說的不准確,在不指定時容量為Integer.MAX_VALUE,不要然的話在put時怎么會受阻呢),但是也可以選擇指定其最大容量,它是基於鏈表的隊列,此隊列按 FIFO(先進先出)排序元素。

  (2)ArrayBlockingQueue在構造時需要指定容量, 並可以選擇是否需要公平性,如果公平參數被設置true,等待時間最長的線程會優先得到處理(其實就是通過將ReentrantLock設置為true來 達到這種公平性的:即等待時間最長的線程會先操作)。通常,公平性會使你在性能上付出代價,只有在的確非常需要的時候再使用它。它是基於數組的阻塞循環隊 列,此隊列按 FIFO(先進先出)原則對元素進行排序。

  (3)PriorityBlockingQueue是一個帶優先級的 隊列,而不是先進先出隊列。元素按優先級順序被移除,該隊列也沒有上限(看了一下源碼,PriorityBlockingQueue是對 PriorityQueue的再次包裝,是基於堆數據結構的,而PriorityQueue是沒有容量限制的,與ArrayList一樣,所以在優先阻塞 隊列上put時是不會受阻的。雖然此隊列邏輯上是無界的,但是由於資源被耗盡,所以試圖執行添加操作可能會導致 OutOfMemoryError),但是如果隊列為空,那么取元素的操作take就會阻塞,所以它的檢索操作take是受阻的。另外,往入該隊列中的元 素要具有比較能力。

  (4)DelayQueue(基於PriorityQueue來實現的)是一個存放Delayed 元素的無界阻塞隊列,只有在延遲期滿時才能從中提取元素。該隊列的頭部是延遲期滿后保存時間最長的 Delayed 元素。如果延遲都還沒有期滿,則隊列沒有頭部,並且poll將返回null。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小於或等於零的值時,則出現期滿,poll就以移除這個元素了。此隊列不允許使用 null 元素.

 

5、代碼例子

 

package is.data.structure.queue;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @ClassName: FruitBasket
 * @Description:
 * 水果籃子
 * @Author: Coding_wxb
 */
public class FruitBasket {
    private boolean close = false;
    BlockingQueue<Fruit> basket = new LinkedBlockingDeque<>(10);
    //存放水果
    public void storeFruit(Fruit fruit) throws InterruptedException{
        basket.put(fruit);
    }
    //取出水果
    public Fruit getFruit() throws InterruptedException{
        return basket.take();
    }
    //獲取籃子中的水果數量
    public int getSize(){
        return basket.size();
    }
    //水果生產者
    class Producer implements Runnable{
        @Override
        public void run() {
            try {
                while (!close){
                    System.out.println("生產者開始生產水果:");
                    Instant start = Instant.now();
                    Fruit fruit1 = new Fruit("read","apple");
                    Fruit fruit2 = new Fruit("yellow","pear");
                    storeFruit(fruit1);
                    storeFruit(fruit2);
                    Instant end = Instant.now();
                    System.out.println("生產水果總耗時:"+Duration.between(start,end).toMillis());
                    System.out.println("生產完水果,籃子中有:"+getSize()+"個水果");
                    Thread.sleep(3000);
                }
            }catch (Throwable e){
                e.printStackTrace();
            }
        }
    }
    //水果消費者
    class Consumer implements  Runnable{

        @Override
        public void run() {
            try {
                while (!close){
                    System.out.println("消費者開始消費水果:");
                    Instant start = Instant.now();
                    Fruit fruit = getFruit();
                    System.out.println("此次消費水果為:"+fruit.toString());
                    System.out.println("生產完水果,籃子中有:"+getSize()+"個水果");
                    Instant end = Instant.now();
                    System.out.println("消費水果總耗時:"+Duration.between(start,end).toMillis());
                    Thread.sleep(3000);
                }
            }catch (Throwable e){
                e.printStackTrace();
            }
        }
    }
    public  void test(){
        ExecutorService ex = Executors.newCachedThreadPool();
        Producer producer = new Producer();
        Consumer consumer = new Consumer();
        ex.submit(producer);
        ex.submit(consumer);
        //程序運行十秒結束
        try {
            Thread.sleep(10000);
        }catch (Throwable e){
            e.printStackTrace();
        }
        ex.shutdownNow();
    }

    public static void main(String[] args) {
        FruitBasket basket = new FruitBasket();
        basket.test();
    }
    //水果類
    class Fruit{
        private String color;
        private String name;

        public Fruit(String color, String name) {
            this.color = color;
            this.name = name;
        }

        @Override
        public String toString() {
            return "Fruit{" +
                    "color='" + color + '\'' +
                    ", name='" + name + '\'' +
                    '}';
        }
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM