Queue常用类解析之BlockingQueue(三):LinkedBlockingQueue

本文深入解析了LinkedBlockingQueue,一个具有容量限制的链表结构阻塞队列。它使用两个独立的锁进行并发控制,允许入队和出队操作并发进行。详细介绍了offer、enqueue、poll、dequeue和remove等核心方法的实现原理,探讨了其并发性能和容量管理策略。
摘要由CSDN通过智能技术生成

Queue常用类解析之PriorityQueue
Queue常用类解析之ConcurrentLinkedQueue
Queue常用类解析之BlockingQueue(一):PriorityBlockingQueue、DelayQueue和DelayedWorkQueue
Queue常用类解析之BlockingQueue(二):ArrayBlockingQueue

接着上文对BlockingQueue的介绍继续向下

六、LinkedBlockingQueue

LinkedBlockingQueue是链表格式的阻塞队列,记录链表的head和last,head的next指向头结点,last指向尾节点,分别用于出队和入队。
LinkedBlockingQueue有容量限制,因此元素入队和出队都有可能阻塞线程。容量默认为Integer.MAX_VALUE。
LinkedBlockingQueue内部含有两个lock锁,分别用于元素入队和出队,因此元素入队和出队是可以并发的。

1. 属性

/** The capacity bound, or Integer.MAX_VALUE if none */
private final int capacity;

/** Current number of elements */
private final AtomicInteger count = new AtomicInteger();

/**
 * Head of linked list.
 * Invariant: head.item == null
 */
transient Node<E> head;

/**
 * Tail of linked list.
 * Invariant: last.next == null
 */
private transient Node<E> last;

/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();

/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();

/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();

/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();

属性都比较常规,没有什么特别的。

2. LinkedBlockingQueue#offer(Object, long, TimeUnit)

public boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException {

    if (e == null) throw new NullPointerException();
    long nanos = unit.toNanos(timeout);
    int c = -1;
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly();
    try {
        while (count.get() == capacity) {
            if (nanos <= 0)
                return false;
            nanos = notFull.awaitNanos(nanos);
        }
        enqueue(new Node<E>(e));
        c = count.getAndIncrement();
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();
    return true;
}

整体流程就是:判空,加putLock锁,判断容量:容量已满的情况下阻塞,入队,更新元素数量,检查并发送notFull信号,释放putLock锁,检查并发送notEmpty信号(需要takeLock锁)。
不明白这儿有必要发送notFull信号,不应该是增加元素发送notEmpty信号,移除元素发送notFull信号吗?

3. LinkedBlockingQueue#enqueue(Node)

private void enqueue(Node<E> node) {
   // assert putLock.isHeldByCurrentThread();
    // assert last.next == null;
    last = last.next = node;
}

具体的入队操作。
节点加载链表尾部,并将新加的节点作为last。

4. LinkedBlockingQueue#poll(long, TimeUnit)
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    E x = null;
    int c = -1;
    long nanos = unit.toNanos(timeout);
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly();
    try {
        while (count.get() == 0) {
            if (nanos <= 0)
                return null;
            nanos = notEmpty.awaitNanos(nanos);
        }
        x = dequeue();
        c = count.getAndDecrement();
        if (c > 1)
            notEmpty.signal();
    } finally {
        takeLock.unlock();
    }
    if (c == capacity)
        signalNotFull();
    return x;
}

整体流程就是:加takeLock锁,判断容量:容量为0的情况下阻塞,出队,更新元素数量,检查并发送notEmpty信号,释放putLock锁,检查并发送notFull信号(需要putLock锁)。

5. LinkedBlockingQueue#dequeue()
private E dequeue() {
    // assert takeLock.isHeldByCurrentThread();
    // assert head.item == null;
    Node<E> h = head;
    Node<E> first = h.next;
    h.next = h; // help GC
    head = first;
    E x = first.item;
    first.item = null;
    return x;
}

head节点从链表中移除,head.next节点作为head节点。

6. LinkedBlockingQueue#remove(Object)
public boolean remove(Object o) {
    if (o == null) return false;
    fullyLock();
    try {
        for (Node<E> trail = head, p = trail.next;
             p != null;
             trail = p, p = p.next) {
            if (o.equals(p.item)) {
                unlink(p, trail);
                return true;
            }
        }
        return false;
    } finally {
        fullyUnlock();
    }
}

remove方法也没有什么特别的,只是其有可能同时影响头节点和尾节点,因此同时需要putLock锁和takeLock锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值