java阻塞队列之LinkedTransferDeque

LinkedBlockingDeque是一种支持双向并发的阻塞队列。

LinkedBlockingDeque特性
1.底层数据结构双向链表
2.同时支持FIFO和FILO,从队列的头和尾同时操作(插入/删除)。
3.线程安全,使用重入锁ReentrantLock和两个Condition来控制并发。
4.容量可选(防止过度膨胀),即可以指定队列的容量。如果不指定,默认容量大小等于Integer.MAX_VALUE。

LinkedBlockingDeque属性
transient Node<E> first; // 头结点
transient Node<E> last; // 尾结点
private transient int count; // 当前队列节点数
private final int capacity; // 队列最大支持容量
final ReentrantLock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
private final Condition notFull = lock.newCondition();

// 节点数据结构
static final class Node<E> {
        E item;
        Node<E> prev;
        Node<E> next;

        Node(E x) {
            item = x;
        }
    }

添加头尾结点

// 头部添加结点
private boolean linkFirst(Node<E> node) {
        if (count >= capacity)
            return false;
        Node<E> f = first;
        node.next = f;
        first = node;
        if (last == null) // 队列只有一个结点
            last = node; // 头尾结点都指向node
        else
            f.prev = node;
        ++count;
        notEmpty.signal(); // 唤醒take阻塞线程
        return true;
    }
// 尾部添加结点
private boolean linkLast(Node<E> node) {
        if (count >= capacity)
            return false;
        Node<E> l = last;
        node.prev = l;
        last = node;
        if (first == null) // 队列只有一个结点
            first = node; // 头尾结点都指向node
        else
            l.next = node;
        ++count;
        notEmpty.signal();
        return true;
    }

移除结点
unlinkFirst、unlinkLast移除头尾结点,unlink(Node<E> x)移除指定结点

void unlink(Node<E> x) {
        Node<E> p = x.prev;
        Node<E> n = x.next; // 先拿到结点x的前后结点
        if (p == null) { // 前缀结点为空,说明x是头节点
            unlinkFirst();
        } else if (n == null) { // 后继结点为空,说明是尾结点
            unlinkLast();
        } else { // p,n相互指向
            p.next = n;
            n.prev = p;
            x.item = null;
            --count;
            notFull.signal();
        }
    }
addFirst(E e)、addLast(E e)分别调用offerFirst(E e)、offerLast(E e),失败会抛出异常!
offerFirst(E e)、offerLast(E e)不能添加null,加锁分别调用linkFirst(Node<E> node)、linkLast(Node<E> node)。
putFirst(E e)、putLast(E e)也不能添加null,分别调用linkFirst(Node<E> node)、linkLast(Node<E> node),添加失败则阻塞。
offerFirst(E e, long timeout, TimeUnit unit)throws InterruptedException
offerLast(E e, long timeout, TimeUnit unit)throws InterruptedException这两个方法会响应中断,不能添加null,在超时时间内会阻塞指定时间,超时后返回false。


LinkedTransferDeque的节点遍历-迭代器iterator
LinkedBlockingDeque支持正向和逆向的两种迭代器,分别是方法Iterator、DescendingIterator。
Iterator和DescendingIterator都继承了AbstractItr内部抽象类,仅仅实现了AbstractItr的以下两个抽象方法firstNode()和nextNode(Node<E> n)。
还有一个可拆分迭代器LBDSpliterator<E>实现implements Spliterator<E>。


抽象类AbstractItr属性与方法
Node<E> next;  // 迭代器实例创建时候拿到的第一个节点
E nextItem; //  迭代器实例创建时候拿到的第一个节点的内容
private Node<E> lastRet; // 上一次调用next()返回的节点,用于remove方法
abstract Node<E> firstNode();
abstract Node<E> nextNode(Node<E> n);

介绍几个AbstractItr的核心方法

/**
 * 返回给定非空节点的后续节点,但可能已被删除。
 */
private Node<E> succ(Node<E> n) {
    for (;;) {
        Node<E> s = nextNode(n);
        if (s == null) // 队列没有更多元素了,空或者到头了
            return null;
        else if (s.item != null) // 有效节点
            return s;
        else if (s == n) // 自链接表示是正常的从队列头或者尾出队,直接取最近的头或尾节点即可
            return firstNode();
        else
            n = s; // s.item ==null表示s是被移除的内部节点,遍历下一个
    }
}

/**
 * 推进节点
 */
void advance() {
    final ReentrantLock lock = LinkedBlockingDeque.this.lock;
    lock.lock();
    try {
        // assert next != null;
        next = succ(next);
        nextItem = (next == null) ? null : next.item;
    } finally {
        lock.unlock();
    }
}

public boolean hasNext() {
    return next != null;
}

public E next() {
    if (next == null)
       throw new NoSuchElementException();
    lastRet = next; // 保留上一次返回的next节点
    E x = nextItem;
    advance();
    return x;
}

public void remove() {
    Node<E> n = lastRet;//remove移除的是上一次调用next方法获取的next节点
    if (n == null)
       throw new IllegalStateException();
    lastRet = null;
    final ReentrantLock lock = LinkedBlockingDeque.this.lock;
    lock.lock();
    try {
       if (n.item != null)
       unlink(n);
    } finally {
       lock.unlock();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值