Java 數據結構基礎學習(隊列)

簡介

隊列是一種特殊的線性表,它只允許在表的前端進行刪除操作,而在表的後端進行插入操作。

Queue接口與List、Set同一級別,都是繼承了Collection接口。LinkedList實現了Deque接 口。Deque接口繼承了Queue接口,因此我們可以把LinkedList當成Queue來用。

應用場景

一般情況下,如果是一些及時消息的處理,並且處理時間很短的情況下是不需要使用隊列的,直接阻塞式的方法調用就可以了。但是,如果在消息處理的時候特別費時間,這個時候如果有新的消息來了,就只能處於阻塞狀態,造成用戶等待。這個時候在項目中引入隊列是十分有必要的。當我們接受到消息後,先把消息放到隊列中,然後再用新的線程進行處理,這個時候就不會有消息的阻塞了。下面就跟大家介紹兩種隊列的使用,一種是基於內存的,一種是基於數據庫的。
————————————————
版權聲明:本文爲CSDN博主「在遠行的路上」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lzy_lizhiyang/article/details/48311925

接口與接口方法

public interface Queue<E> extends Collection<E> {
    /**
     * 如果可能,將指定的元素插入到此隊列中
     * 在不違反容量限制的情況下,立即返回
     * 如果無法在此處添加元素,則拋出 IllegalStateException
     * 如果指定元素的類阻止它被添加到此隊列中,則拋出 ClassCastException        
     * 如果指定的元素爲空且此隊列不允許空元素,則拋出 NullPointerException
     * 如果該元素的某些屬性阻止它被添加到此隊列中,則拋出 IllegalArgumentException
     */
    boolean add(E e);

    /**
     * 如果可以在不違反容量限制的情況下立即將指定的元素插入到此隊列中。
     * 
     * 當使用受容量限制的隊列時,這種方法通常優於add ,後者只能通過拋出異常來插入元素。
     *
     * @param e 要添加的元素
     * @return 添加元素如果隊列已滿直接返回false,隊列未滿則直接插入並返回true
     * @throws 如果指定元素的類阻止它被添加到此隊列中,則拋出 ClassCastException
     * 如果指定的元素爲空且此隊列不允許空元素,則拋出 NullPointerException
     * 如果該元素的某些屬性阻止它被添加到此隊列中,則拋出 IllegalArgumentException
     */
    boolean offer(E e);

    /**
     * 檢索並移除此隊列的頭部。 此方法與poll ()的不同之處在於,如果隊列爲空,它將引發異常。
     *
     * 返回此隊列的頭部
     * 如果隊列爲空,則拋出 NoSuchElementException
     */
    E remove();

    /**
     * 檢索並移除此隊列的頭部,如果此隊列爲空,則返回null。
     */
    E poll();

    /**
     * 檢索但不移除此隊列的頭部。 此方法與peek的不同之處在於,如果隊列爲空,它將引發異常。
     * 返回此隊列的頭部
     * 如果隊列爲空,則拋出 NoSuchElementException
     */
    E element();

    /**
     * 檢索但不移除此隊列的頭部。 此方法與peek的不同之處在於,如果隊列爲空,它將返回null。
     *
     * 返回此隊列的頭部,如果該隊列爲空,則返回{@code null }
     */
    E peek();
}

常用隊列

阻塞隊列和普通隊列(BlockingQueue)

阻塞隊列是一個支持兩個附加操作的隊列。這兩個附加的操作支持阻塞的插入和移除方法。

這兩個附加的操作是:在隊列爲空時,獲取元素的線程會等待隊列變爲非空。當隊列滿時,存儲元素的線程會等待隊列可用。

阻塞隊列常用於生產者和消費者的場景,生產者是往隊列裏添加元素的線程,消費者是從隊列裏拿元素的線程。阻塞隊列就是生產者存放元素的容器,而消費者也只從容器裏拿元素。

BlockingQueue 核心方法(區別於Queue)

 //將元素設置到隊列中,如果隊列中沒有多餘的空間,該方法會一直阻塞,直到隊列中有多餘的空間。
    void put(E e) throws InterruptedException;

    //將給定元素在給定的時間內設置到隊列中,如果設置成功返回true, 否則返回false.
    boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException;

    //從隊列中獲取值,如果隊列中沒有值,線程會一直阻塞,直到隊列中有值,並且該方法取得了該值。
    E take() throws InterruptedException;

    //在給定的時間裏,從隊列中獲取值,如果沒有取到會拋出異常。
    E poll(long timeout, TimeUnit unit)
        throws InterruptedException;

    //獲取隊列中剩餘的空間。
    int remainingCapacity();
    
    //從隊列中移除指定的值。
    boolean remove(Object o);

    //判斷隊列中是否擁有該值。
    public boolean contains(Object o);

    //將隊列中值,全部移除,併發設置到給定的集合中。
    int drainTo(Collection<? super E> c);

    //指定最多數量限制將隊列中值,全部移除,併發設置到給定的集合中。
    int drainTo(Collection<? super E> c, int maxElements);
    

BlockingQueue的子類用法,詳見Java中阻塞隊列的使用

阻塞隊列(LinkedBlockingQueue)和非阻塞隊列(ConcurrentLinkedQueue)

1.LinkedBlockingQueue是使用鎖機制,ConcurrentLinkedQueue是使用CAS算法,雖然LinkedBlockingQueue的底層獲取鎖也是使用的CAS算法
2.關於取元素,ConcurrentLinkedQueue不支持阻塞去取元素,LinkedBlockingQueue支持阻塞的take()方法。
3.關於插入元素的性能,但在實際的使用過程中,尤其在多cpu的服務器上,有鎖和無鎖的差距便體現出來了,ConcurrentLinkedQueue會比LinkedBlockingQueue快很多。
————————————————
版權聲明:本文爲CSDN博主「IT劉華強」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/jiguquan3839/article/details/84342720

結語

最近發現工作中百度次數越來越多,發現自己的數據結構存在了很大問題。於是打算回過頭重新把數據結構重新學習一下,於是結合網上的一些資源與自己的學習整理一下這方面的知識。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章