Collection框架之Queue

1.结构

队列是元素的序列,在队列中:
(1) 只能在队列尾进行插入
(2) 只能在队列头进行删除,获取和修改
队列的这种定义有时被称为”先来先服务”.在Java中也实现了队列,先看一下结构吧.
这里写图片描述

在这里,我只看了这3个类,分别是数组阻塞队列,优先级队列,优先级阻塞队列.

2.ArrayBlockingQueue

2.1 字段

    private static final long serialVersionUID = -817911632652898426L;

    /** The queued items */
    final Object[] items;

    /** items index for next take, poll, peek or remove */
    int takeIndex;

    /** items index for next put, offer, or add */
    int putIndex;

    /** Number of elements in the queue */
    int count;

    /*
     * Concurrency control uses the classic two-condition algorithm
     * found in any textbook.
     */

    /** Main lock guarding all access */
    final ReentrantLock lock;
    /** Condition for waiting takes */
    private final Condition notEmpty;
    /** Condition for waiting puts */
    private final Condition notFull;

serialVersionUID:序列化ID
items:队列的元素集合
takeIndex:队列头下表
putIndex:队列尾下表
count:队列的长度
lock,notEmpty,notFull:和线程相关,用于阻塞.

2.2 构造器

public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }
 public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

public ArrayBlockingQueue(int capacity, boolean fair,
                              Collection<? extends E> c) {
        this(capacity, fair);

        final ReentrantLock lock = this.lock;
        lock.lock(); // Lock only for visibility, not mutual exclusion
        try {
            int i = 0;
            try {
                for (E e : c) {
                    checkNotNull(e);
                    items[i++] = e;
                }
            } catch (ArrayIndexOutOfBoundsException ex) {
                throw new IllegalArgumentException();
            }
            count = i;
            putIndex = (i == capacity) ? 0 : i;
        } finally {
            lock.unlock();
        }
    }

第三个构造器中如果capacity < c.size()时,会抛出IllegalArgumentException异常.其中关于ReentrantLock类和Condition类可以看这篇博客:http://blog.csdn.net/ghsau/article/details/7481142

2.3 add方法

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

super.add方法如下:

 public boolean add(E e) {
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

接着看子类实现的offer方法:

public boolean offer(E e) {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            if (count == items.length)
                return false;
            else {
                insert(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }

该方法是同步的,如果已经满了,return false,否则insert(e).

insert方法如下:

private void insert(E x) {
        items[putIndex] = x;
        putIndex = inc(putIndex);
        ++count;
        notEmpty.signal();
    }

final int inc(int i) {
        return (++i == items.length) ? 0 : i;
    }

在这里putIndex和takeIndex相当于指针,假如items = new Object[4];items.length=4,此时:
这里写图片描述
当add(“2”),add(“3”),add(“4”),remove()这3个操作后,如下:
这里写图片描述
再add(“haha”),add(“hehe”)后,如下:
这里写图片描述

继续add方法,可以看出inc方法是一个循环,在索引0位置的元素跟随在索引items最大元素的后面,它的好处是add操作只需要常量时间.而不用扩展数组.
其中的notEmpty.signal()方法作用是唤醒读线程,也相当于说”我有数据了,可以来取了”.

2.4 put方法

public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            insert(e);
        } finally {
            lock.unlock();
        }
    }

put方法与add方法最大的不同是:当count == items.length时,add方法选择返回false,提示已经满了.而put方法是使用阻塞,notFull.await()方法表示阻塞写线程 ,当读线程读完后执行notFull.signal() 使该方法执行.

2.5 take方法

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

notEmpty.await()方法是阻塞读线程.
extract方法如下:

   private E extract() {
        final Object[] items = this.items;
        E x = this.<E>cast(items[takeIndex]);
        items[takeIndex] = null;
        takeIndex = inc(takeIndex);
        --count;
        notFull.signal();
        return x;
    }

读线程读完后执行notFull.signal() 唤醒写进程.

3.PriorityQueue

3.1 字段

    private static final long serialVersionUID = -7720805057305804111L;

    private static final int DEFAULT_INITIAL_CAPACITY = 11;
    private transient Object[] queue;
    private int size = 0;

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

     /**
     * The comparator, or null if priority queue uses elements'
     * natural ordering.
     */
    private final Comparator<? super E> comparator;

    /**
     * The number of times this priority queue has been
     * <i>structurally modified</i>.  See AbstractList for gory details.
     */
    private transient int modCount = 0;

与ArrayBlockingQueue最大的区别是拥有一个比较器comparator.

3.2 构造器

 public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }
public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

使用默认的构造器是queue大小为DEFAULT_INITIAL_CAPACITY = 11.

3.3 add方法(offer方法)

public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }

grow方法用于扩展数组,方法如下:

 private void grow(int minCapacity) {
        int oldCapacity = queue.length;
        // Double size if small; else grow by 50%
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                         (oldCapacity + 2) :
                                         (oldCapacity >> 1));
        // overflow-conscious code
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        queue = Arrays.copyOf(queue, newCapacity);
    }

该方法和ArrayList中的扩展数组方法十分相似,不过这里是数组长度超过64时扩展一半,而ArrayList是始终扩展一半.

siftUp方法如下:

private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }

private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }

private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

如果有比较器的话,直接使用comparator.compare(x, (E) e),而没有的话使用key的默认构造器.

下面的while方法使用的二分法查找插入的位置,其中的int parent = (k - 1) >>> 1;就是将k-1无符号的向右移一位.

4.PriorityBlockingQueue

该类就是PriorityQueue类中加入ReentrantLock类和Condition类,实现方式和ArrayBlockingQueue十分相似.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值