Java 7之多线程并发容器 - ArrayBlockingQueue(二)

2014-11-24 02:36:22 · 作者: · 浏览: 6
调用offer()方法添加元素,成功返回true,失败则抛出异常,表示队列已经满了。

(2)offer(E e)方法如果队列满了,则返回false,否则调用insert()方法进行元素的插入,这个方法的源代码如下:

 private void insert(E x) {
        items[putIndex] = x;
        putIndex = inc(putIndex);
        ++count;                 // 元素数量加1
        notEmpty.signal();       // 唤醒取元素的线程
 }

理解如上代码,首先要认识两个变量的含义:takeIndex和putIndex。takeIndex表示下一个被取出元素的索引,putIndex表示下一个被添加元素的索引。它们的定义如下:

int takeIndex; // 下一个被取出元素的索引
int putIndex;  // 下一个被添加元素的索引

其中inc()的源代码如下:

final int inc(int i) {
    return (++i == items.length)   0 : i;
}
当i加1后如果队列已经满了,则设置下一个被添加元素的索引为0.

(3) put(E e)方法当加入元素时,如果队列已经满了,则阻塞等待;直到检测到不满时调用insert()方法进行插入。

(4)offer(E e, long timeout, TimeUnit unit) 如果在指定的时间内还无法插入队列,则返回false,表示插入失败。否则让插入队列等待一定的时间。如果插入成功,则返回true。


2、删除元素


    public boolean remove(Object o) {
        if (o == null) return false;
        final Object[] items = this.items;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) {
                if (o.equals(items[i])) {
                    removeAt(i);
                    return true;
                }
            }
            return false;
        } finally {
            lock.unlock();
        }
    }
    public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return (count == 0)   null : extract();
        } finally {
            lock.unlock();
        }
    }

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

    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0) {
                if (nanos <= 0)
                    return null;
                nanos = notEmpty.awaitNanos(nanos);
            }
            return extract();
        } finally {
            lock.unlock();
        }
    }
(1)remove(Object o)方法会移除元素值相同的元素。在移除过程中需要使用removeAt()方法,如下:

   void removeAt(int i) {                 // 移除索引处理的元素
        final Object[] items = this.items;
        // if removing front item, just advance
        if (i == takeIndex) {
            items[takeIndex] = null;
            takeIndex = inc(takeIndex); // 下一个要取出元素的索引
        } else {
            // slide over all others up through putIndex.
            for (;;) {
                int nexti = inc(i);
                if (nexti != putIndex) {
                    items[i] = items[nexti];
                    i = nexti;
                } else {
                    items[i] = null;
                    putIndex = i;
                    break;
                }
            }
        }
        --count;
        notFull.signal();             // 通知生产线程
    }


(2)使用poll()方法时调用exact()方法,取出takeIndex索引处的值后删除这个元素,源代码如下:

private E extract() {
    final Object[] items = this.items;
    // 强制将元素转换为泛型E
    E x = this.
  
   cast(items[takeIndex]);
    // 将第takeIndex元素设为null,即删除。同时,帮助GC回收
    items[takeIndex] = null;
    // 设置下一个被取出元素的索引
    takeIndex = inc(takeIndex);
    --count;
    notFull.signal();
    return x;
}
  

(3)take()方法调用时,如果此时队列为空,则阻塞等待;否则调用extract()方法返回元素值。

(4)poll(long timeout, TimeUnit unit) 在指定的时间内队列仍然为空则阻塞,超过指定时间返回null;队列不空直接调用extract()方法返回元素值。



3、查找元素

public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return (count == 0)   null : itemAt(takeIndex);
        } finally {
            lock.unlock();
        }
    }
如果队列为空,则返回null,否则调用itemAt()方法获取元素,如下:

 final E itemAt(int i) {
        return this.
  
   cast(items[i]);
 }
  
这个类还继承了AbstractQueue中的一个element()方法,如下:

  public E element() {
        E x = peek();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }
调用peek()方法查找,如果元素存在,则返回,否则抛出异常。


4、遍历元素

public Iterator
  
    iterator() {
    return new Itr();
}
  
private class Itr implements Iterator
  
    {
    // 队列中剩余元素的个数
    private int remaining; // Number of elements yet to be returned
    // 下一次调用next()返回的元素的索引
    private int nextIndex; // Index of element to be returned by next
    // 下一次调用next()返回的元素
    private E nextItem;    // Element to be re