阻塞队列

来源:互联网 发布:怎么申请淘宝主播 编辑:程序博客网 时间:2024/05/24 15:41
转载自:http://www.infoq.com/cn/articles/java-blocking-queue/
              http://blog.csdn.net/z69183787/article/details/52055937

什么是阻塞队列

       阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。

       阻塞队列提供了四种处理方法:

 操作  抛出异常返回特殊值    阻塞        超时退出 插入   add(e)    offer(e)  put(e)   offer(e,time,unit) 移除  remove()     poll()  take()      poll(time,unit) 检查  element()     peek()  不可用            不可用

       抛出异常:是指当阻塞队列满时候,再往队列里插入元素,会抛出IllegalStateException(“Queue full”)异常。当队列为空时,从队列里获取元素时会抛出NoSuchElementException异常 。
       返回特殊值:插入方法会返回是否成功,成功则返回true。移除方法,则是从队列里拿出一个元素,如果没有则返回null。
       阻塞:当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到拿到数据,或者响应中断退出。当队列空时,消费者线程试图从队列里take元素,队列也会阻塞消费者线程,直到队列可用。
       超时退出:当阻塞队列满时,队列会阻塞生产者线程一段时间,如果超过一定的时间,生产者线程就会退出。

Java里的阻塞队列

JDK7提供了7个阻塞队列。分别是
       ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
       LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
       PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
       DelayQueue:一个使用优先级队列实现的无界阻塞队列。
       SynchronousQueue:一个不存储元素的阻塞队列。
       LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
       LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

DelayQueue

       DelayQueue是一个支持延时获取元素的无界阻塞队列。队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延迟期满时才能从队列中提取元素。可以将DelayQueue运用在以下应用场景:
       缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。
       定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,从比如TimerQueue就是使用DelayQueue实现的。
       队列中的元素必须implements Delayed接口,实现getDelay方法,该方法应该返回以纳秒为单位的时间差,同时实现compareTo来指定元素的顺序,让延时时间最长的放在队列的末尾。简单的示例代码如下:
class DelayedItem<T> implements Delayed{    private T t;    private long liveTime ;    private long removeTime;        public DelayedItem(T t,long liveTime){        this.setT(t);        this.liveTime = liveTime;        this.removeTime = TimeUnit.NANOSECONDS.convert(liveTime, TimeUnit.NANOSECONDS) + System.nanoTime();    }        @Override    public int compareTo(Delayed o) {        if (o == null) return 1;        if (o == this) return  0;        if (o instanceof DelayedItem){            DelayedItem<T> tmpDelayedItem = (DelayedItem<T>)o;            if (liveTime > tmpDelayedItem.liveTime ) {                return 1;            }else if (liveTime == tmpDelayedItem.liveTime) {                return 0;            }else {                return -1;            }        }        long diff = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);        return diff > 0 ? 1:diff == 0? 0:-1;    }    @Override    public long getDelay(TimeUnit unit) {        return unit.convert(removeTime - System.nanoTime(), unit);    }    public T getT() {        return t;    }    public void setT(T t) {        this.t = t;    }    @Override    public int hashCode(){        return t.hashCode();    }        @Override    public boolean equals(Object object){        if (object instanceof DelayedItem) {            return object.hashCode() == hashCode() ?true:false;        }        return false;    }}
SynchronousQueue
       SynchronousQueue是一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。SynchronousQueue可以看成是一个传球手,负责把生产者线程处理的数据直接传递给消费者线程。队列本身并不存储任何元素,非常适合于传递性场景,比如在一个线程中使用的数据,传递给另外一个线程使用,SynchronousQueue的吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue。

LinkedTransferQueue
       LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列。相对于其他阻塞队列,LinkedTransferQueue多了tryTransfer和transfer方法。
       ransfer方法:如果当前有消费者正在等待接收元素,transfer方法可以把生产者传入的元素立刻transfer(传输)给消费者。如果没有消费者在等待接收元素,transfer方法会将元素存放在队列的tail节点,并等到该元素被消费者消费了才返回。
       tryTransfer方法:用来试探下生产者传入的元素是否能直接传给消费者。如果没有消费者等待接收元素,则返回false。和transfer方法的区别是tryTransfer方法无论消费者是否接收,方法立即返回。而transfer方法是必须等到消费者消费了才返回。对于带有时间限制的tryTransfer(E e, long timeout, TimeUnit unit)方法,则是试图把生产者传入的元素直接传给消费者,但是如果没有消费者消费该元素则等待指定的时间再返回,如果超时还没消费元素,则返回false,如果在超时时间内消费了元素,则返回true。

LinkedBlockingDeque
       LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列。所谓双向队列是指可以从队列的两端插入和移出元素。双端队列因为多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。相比其他的阻塞队列,LinkedBlockingDeque多了addFirst,addLast,offerFirst,offerLast,peekFirst,peekLast等方法,以First结尾的方法,表示插入,获取(peek)或移除双端队列的第一个元素。以Last结尾的方法,表示插入,获取或移除双端队列的最后一个元素。另外插入方法add等同于addLast,移除方法remove等效于removeFirst。但是take方法却等同于takeFirst。
0 0