首页 > 代码库 > Java里的阻塞队列
Java里的阻塞队列
JDK7提供了7个阻塞队列,如下:
ArrayBlockingQueue : 一个数组结构组成的有界阻塞队列。
LinkedBlockingQueue : 一个由链表结构组成的有界阻塞队列 。
PriorityBlockingQueue : 一个支持优先级排序的无界阻塞队列 。
DelayQueue : 一个使用优先级队列实现的无界阻塞队列 。
SynchronousQueue : 一个不存储元素的阻塞队列 。
LinkedTransferQueue : 一个由链表结构组成的无界阻塞队列 。
LinkedBlockingDeque : 一个由链表结构组成的双向阻塞队列 。
下面分别介绍几个队列 :
1.ArrayBlockingQueue
ArrayBlockingQueue是一个由数组结构组成的有界阻塞队列,此队列按照FIFO的原则对元素进行排序 。
默认情况下不保证线程公平的访问队列,所谓公平的访问队列是指阻塞的线程,可以按照阻塞的先后顺序访问队列,即先阻塞线程先访问队列。非公平性是对先等待的线程是非公平的,当队列可用时,阻塞的线程都可以争夺队列的资格,有可能先阻塞的队列最后才访问队列。为了保证公平性通常都会降低吞吐量。下面的代码可以创建一个公平的阻塞队列:
ArrayBlockingQueue fairQueue = new ArrayBlockingQueue(100,true);
访问者的公平性是通过可重入锁实现的,构造函数如下:
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(); }
ArrayBlockingQueue使用一个Object数组保存数据,一个int类型的count表示当前队列添加的元素个数,有界保证依靠的两个Condition对象,下面看一下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(); } } private void insert(E x) { items[putIndex] = x; putIndex = inc(putIndex);//加1 ++count; notEmpty.signal(); }
ArrayBlockingQueue在执行put操作时,首先获取锁,然后判断插入队列是否已满,如果队列已满则等待,否则顺利插入,并且执行一次notEmpty.signal()唤醒有可能队列为空的情况下执行take()操作在等待的线程 ,take()方法代码如下:
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { //如果队列为空,则等待元素入队 while (count == 0) notEmpty.await(); return extract(); } finally { lock.unlock(); } } 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; }
take操作也是先判断队列是否为空,为空则等待,不为空则返回items[takeIndex] ,并且执行notFull.signal()唤醒可能在等待put操作的线程。
2.LinkedBlockingQueue
Java里的阻塞队列