BlockingQueue

BlockingQueue

  1. BlockingQueue不接受空元素。实现在试图添加、放置或提供空值时抛出NullPointerException。null用作标记值,表示轮询操作失败。
  2. 容量有一个最大值限制,如果超过这个容量,则会阻塞,(但不是必须设置最大容量,例如,PriorityBlockQueue 不设置最大值,但受限于数组的最大容量)
  3. 记住 BlockingQueue 不能插入 null, add, offer, put
  4. 其中,尽量不要使用 remove 方法,因为要利用循环删除元素,并且还要进行前移元素,因此开销较大。并且 remove 每次只能删除一个元素。

add

如果可以在不超过队列容量的情况下立即插入指定的元素,成功后返回true,如果队列已满则抛出IllegalStateException,则在此队列的末尾插入指定的元素。

public boolean add(E e) {
    return super.add(e);
}

Offer

如果队列未满,则插入,如果已满,则返回 false

如果 插入元素 为 null ; 则抛出异常

/**
     * Inserts the specified element at the tail of this queue if it is
     * possible to do so immediately without exceeding the queue's capacity,
     * returning {@code true} upon success and {@code false} if this queue
     * is full.  This method is generally preferable to method {@link #add},
     * which can fail to insert an element only by throwing an exception.
     *
     * @throws NullPointerException if the specified element is null
     */
public boolean offer(E e) {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lock(); // 获取锁
    try {
        if (count == items.length)
            return false;
        else {
            enqueue(e);
            return true;
        }
    } finally {
        lock.unlock();  // 释放锁
    }
}

offer

插入,提供阻塞时长

/**
         * Inserts the specified element at the tail of this queue, waiting
         * up to the specified wait time for space to become available if
         * the queue is full.
         *
         * @throws InterruptedException {@inheritDoc}
         * @throws NullPointerException {@inheritDoc}
         */
public boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException {

    checkNotNull(e);
    long nanos = unit.toNanos(timeout);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length) {
            if (nanos <= 0)
                return false;
            nanos = notFull.awaitNanos(nanos);
        }
        enqueue(e);
        return true;
    } finally {
        lock.unlock();
    }
}

checkNotNull

查看当前是否为空

private static void checkNotNull(Object v) {
    if (v == null)
        throw new NullPointerException();
}

enqueue

插入元素,操作实在有锁的前提下

notEmpty.signal(); 还未解决

/**
     * Inserts element at current put position, advances, and signals.
     * Call only when holding lock.
     */
private void enqueue(E x) {
    // assert lock.getHoldCount() == 1;
    // assert items[putIndex] == null;
    final Object[] items = this.items;
    // putIndex 是当前要插入的元素
    items[putIndex] = x; 
    /*
      然后把 putIndex ++ ; 因为是循环链表,因此要把 putIndex = 0; 不用担心 
   	  putIndex == takeIndex, 因为 在 offer 中已经判断 count == item.size()  是否满了,返		  回false    
    */
    if (++putIndex == items.length)
        putIndex = 0;
    count++; // 容量自增
    notEmpty.signal(); // 
}

put

插入

/**
     * Inserts the specified element at the tail of this queue, waiting
     * for space to become available if the queue is full.
     *
     * @throws InterruptedException {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly(); // 
    try {
        while (count == items.length)
            notFull.await();
        enqueue(e); // 插入
    } finally {
        lock.unlock(); // 释放锁
    }
}

poll

public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        // 如果 为空,则返回 null
        return (count == 0) ? null : dequeue();
    } finally {
        lock.unlock();
    }
}

dequeue

删除元素,并且把当前元素赋值为 null ; 并且 takeIndex ++;

/**
 * Extracts element at current take position, advances, and signals.
 * Call only when holding lock.
 */
private E dequeue() {
    // assert lock.getHoldCount() == 1;
    // assert items[takeIndex] != null;
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    E x = (E) items[takeIndex];
    items[takeIndex] = null;
    if (++takeIndex == items.length)
        takeIndex = 0;
    count--;
    if (itrs != null)
        itrs.elementDequeued();
    notFull.signal();
    return x;
}

remainingCapacity

该方法是为了找出队列剩余容量

返回此队列在理想情况下(在没有内存或资源约束的情况下)可以不阻塞地接受的附加元素的数量;
虽然该方法时线程安全的,但是如果希望通过该方法查询是否有空余元素,然后再插入或者删除,就变成了符合操作,也就是非线程安全的。
// this doc comment is a modified copy of the inherited doc comment,
// without the reference to unlimited queues.
/**
 * Returns the number of additional elements that this queue can ideally
 * (in the absence of memory or resource constraints) accept without
 * blocking. This is always equal to the initial capacity of this queue
 * less the current {@code size} of this queue.
 *
 * <p>Note that you <em>cannot</em> always tell if an attempt to insert
 * an element will succeed by inspecting {@code remainingCapacity}
 * because it may be the case that another thread is about to
 * insert or remove an element.
 */
public int remainingCapacity() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return items.length - count;
    } finally {
        lock.unlock();
    }
}

take

如果,队列为空,则会陷入阻塞

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

remove

/**
 * Removes a single instance of the specified element from this queue,
 * if it is present.  More formally, removes an element {@code e} such
 * that {@code o.equals(e)}, if this queue contains one or more such
 * elements.
 * Returns {@code true} if this queue contained the specified element
 * (or equivalently, if this queue changed as a result of the call).
 *
 * <p>Removal of interior elements in circular array based queues
 * is an intrinsically slow and disruptive operation, so should
 * be undertaken only in exceptional circumstances, ideally
 * only when the queue is known not to be accessible by other
 * threads.
 *
 * @param o element to be removed from this queue, if present
 * @return {@code true} if this queue changed as a result of the call
 */
public boolean remove(Object o) {
    if (o == null) return false;
    final Object[] items = this.items;
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        if (count > 0) {
            final int putIndex = this.putIndex;
            int i = takeIndex;
            // 通过循环找出 元素,然后确定下标
            do {
                if (o.equals(items[i])) {
                    removeAt(i);
                    return true;
                }
                if (++i == items.length)
                    i = 0;
            } while (i != putIndex);
        }
        return false;
    } finally {
        lock.unlock();
    }
}
/**
     * Deletes item at array index removeIndex.
     * Utility for remove(Object) and iterator.remove.
     * Call only when holding lock.
     */
void removeAt(final int removeIndex) {
    // assert lock.getHoldCount() == 1;
    // assert items[removeIndex] != null;
    // assert removeIndex >= 0 && removeIndex < items.length;
    final Object[] items = this.items;
    if (removeIndex == takeIndex) {
        // 如果当前 就是 应该弹出的元素
        // removing front item; just advance
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
    } else {
        // an "interior" remove
        // slide over all others up through putIndex.
        final int putIndex = this.putIndex;
        // 
        for (int i = removeIndex;;) {
            int next = i + 1;
            if (next == items.length)
                next = 0;
            if (next != putIndex) {
                // 如果 下一个元素不是最后一个
                items[i] = items[next];
                i = next;
            } else {
                items[i] = null;
                this.putIndex = i;
                break;
            }
        }
        count--;
        if (itrs != null)
            itrs.removedAt(removeIndex);
    }
    notFull.signal();
}

toArray(无参)

这个函数比较有意思,是把当前队列中的元素复制到一个新数组中,并不是队列的容量大小,而是队列的真实元素个数

/**
 * Returns an array containing all of the elements in this queue, in
 * proper sequence.
 *
 * <p>The returned array will be "safe" in that no references to it are
 * maintained by this queue.  (In other words, this method must allocate
 * a new array).  The caller is thus free to modify the returned array.
 *
 * <p>This method acts as bridge between array-based and collection-based
 * APIs.
 *
 * @return an array containing all of the elements in this queue
 */
public Object[] toArray() {
    Object[] a;
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        final int count = this.count;
        a = new Object[count];
        // 这里的 n  表示从 takeIndex 到 末尾的元素的个数
        int n = items.length - takeIndex;
        //
        if (count <= n)
            // 表示 putIndex 在 takeIndex 之后
            System.arraycopy(items, takeIndex, a, 0, count);
        else {
            // 表示 putIndex 在 takeIndex 之前
            System.arraycopy(items, takeIndex, a, 0, n);
            System.arraycopy(items, 0, a, n, count - n);
        }
    } finally {
        lock.unlock();
    }
    return a;
}

toArray(T[] a)

这个有参数的 可以运行时获取数组类型的对象,而不是返回 Object 类型的数组,因为我们知道将 Object 的数组转化成其他数组 会出现异常

public <T> T[] toArray(T[] a) {}

  1. 要记住 返回值的类型必须和参数类型相同,因此,可以利用 T 类型或者T类型的父类类型数组接受

  2. a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), count);

可以看到 a.getClass().getCOmponentType() 其实是获取元素的真实类型,也就是说有可能是 T 类型的子类,但是又强制类型转换成了 T[];

  1. if (len < count) 如果 参数数组的长度小于 count ;则重新分配

  2. if(len > count) ; 如果 参数数组容量大于 count, 则记得把最后一个元素设置成 null; 用于记录最后一个元素

clear

其实,这个方法就是简单的清空数据元素, 但有一点 takeIndex 和 putIndex 不一定等于 0

for (; k > 0 && lock.hasWaiters(notFull); k--)
    notFull.signal();

其实,我们知道,其实阻塞队列是基于条件队列实现的, 当 数组存储满的时候, notFull.await

但是,take 数组之后,就需要 notFull.signal()

clear 其实就是一种 出队列,因此,将 notFull 阻塞队列的元素唤醒。

/**
 * Atomically removes all of the elements from this queue.
 * The queue will be empty after this call returns.
 */
public void clear() {
    final Object[] items = this.items;
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        int k = count;
        if (k > 0) {
            final int putIndex = this.putIndex;
            int i = takeIndex;
            do {
                items[i] = null;
                if (++i == items.length)
                    i = 0;
            } while (i != putIndex);
            takeIndex = putIndex;
            count = 0;
            if (itrs != null)
                itrs.queueIsEmpty();
            for (; k > 0 && lock.hasWaiters(notFull); k--)
                notFull.signal();
        }
    } finally {
        lock.unlock();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值