java三種隊列詳解:java雙端隊列作用

LinkedBlockingDeque概述

LinkedBlockingDeque是由鏈表構成的界限可選的雙端阻塞隊列,支持O(1)的時間複雜度從兩端插入和移除元素,如不指定邊界,則為Integer.MAX_VALUE。

由一個ReentrantLock保證同步,使用conditions來實現等待通知。

Java並發包源碼學習系列:LBD雙端阻塞隊列源碼解析

類圖結構及重要字段

Java並發包源碼學習系列:LBD雙端阻塞隊列源碼解析
public class LinkedBlockingDeque<E>
    extends AbstractQueue<E>
    implements BlockingDeque<E>, java.io.Serializable {

    private static final long serialVersionUID = -387911632671998426L;

    /** 雙向鏈表節點 */
    static final class Node<E> {
        E item;
        Node<E> prev;
        Node<E> next;
        Node(E x) {
            item = x;
        }
    }

    /**
     * 指向第一個節點
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * 指向最後一個節點
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

    /** 節點數量 */
    private transient int count;

    /** 隊列容量 */
    private final int capacity;

    /** 保證同步 */
    final ReentrantLock lock = new ReentrantLock();

    /** take操作發生的條件 */
    private final Condition notEmpty = lock.newCondition();

    /** put操作發生的條件 */
    private final Condition notFull = lock.newCondition();
    
}

linkFirst

嘗試將節點加入到first之前,更新first,如果插入之後超出容量,返回false。

private boolean linkFirst(Node<E> node) {
        // assert lock.isHeldByCurrentThread();
        if (count >= capacity)
            return false;
        Node<E> f = first;
        node.next = f;
        first = node;
        if (last == null)
            last = node;
        else
            f.prev = node;
        ++count;
        notEmpty.signal();
        return true;
    }
Java並發包源碼學習系列:LBD雙端阻塞隊列源碼解析

linkLast

在last節點後加入節點node,更新last。如果插入之後超出容量,返回false。

private boolean linkLast(Node<E> node) {
        // assert lock.isHeldByCurrentThread();
        if (count >= capacity)
            return false;
        Node<E> l = last;
        node.prev = l;
        last = node;
        if (first == null)
            first = node;
        else
            l.next = node;
        ++count;
        notEmpty.signal();// 滿足notEmpty條件
        return true;
    }
Java並發包源碼學習系列:LBD雙端阻塞隊列源碼解析

unlinkFirst

移除first節點,並返回其item值,如果隊列為空,則返回full。

private E unlinkFirst() {
        // assert lock.isHeldByCurrentThread();
        Node<E> f = first;
        if (f == null)
            return null;
        Node<E> n = f.next;
        E item = f.item;
        f.item = null;
        f.next = f; // help GC
        first = n;
        if (n == null)
            last = null;
        else
            n.prev = null;
        --count;
        notFull.signal();// 滿足notFull條件
        return item;
    }
Java並發包源碼學習系列:LBD雙端阻塞隊列源碼解析

unlinkLast

移除last節點,並返回其item值,如果隊列為空,則返回full。

private E unlinkLast() {
        // assert lock.isHeldByCurrentThread();
        Node<E> l = last;
        if (l == null)
            return null;
        Node<E> p = l.prev;
        E item = l.item;
        l.item = null;
        l.prev = l; // help GC
        last = p;
        if (p == null)
            first = null;
        else
            p.next = null;
        --count;
        notFull.signal(); // 滿足notFull條件
        return item;
    }
Java並發包源碼學習系列:LBD雙端阻塞隊列源碼解析

unlink

移除任意一個節點,注意這裡並沒有操作x本身的連接,因為它可能仍被iterator使用着。

void unlink(Node<E> x) {
        // assert lock.isHeldByCurrentThread();
        Node<E> p = x.prev;
        Node<E> n = x.next;
        // 移除的是first
        if (p == null) {
            unlinkFirst();
        // 移除的是last
        } else if (n == null) {
            unlinkLast();
        } else {
            // 移除的是中間節點
            p.next = n;
            n.prev = p;
            x.item = null;
            // Don't mess with x's links.  They may still be in use by
            // an iterator.
            // 這裡x的prev和next指針都沒有改變,因為他們可能在被iterator使用
            --count;
            notFull.signal();
        }
    }
Java並發包源碼學習系列:LBD雙端阻塞隊列源碼解析

總結

LinkedBlockingDeque是由鏈表構成的界限可選的雙端阻塞隊列,支持O(1)的時間複雜度從兩端插入和移除元素,如不指定邊界,則為Integer.MAX_VALUE。

由一個ReentrantLock保證同步,使用conditions來實現等待通知。

上面介紹的所有操作基本上就是核心方法啦,諸如putFirst、putLast、takeFirst、takeLast等方法都會調用上面的核心方法,而且實現上面也是比較簡單的,就是雙端鏈表的基本操作,不懂的可以畫畫圖幫助理解哈。

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/223369.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-09 14:18
下一篇 2024-12-09 14:18

相關推薦

發表回復

登錄後才能評論