DelayQueue要点解析

    DelayQueue,顾名思义,是具有延迟功能的队列,名字没有表现出来的还有一个功能就是优先级队列,它的实现依赖了我们熟知的PriorityQueue,很棒哈。当然,想进入这个队列的元素自身必须先实现Delayed接口和Comparable接口,她只有两个构造函数,默认的就不说了,另一个就是参数为Collection的构造函数,但是你可以通过这个Collection传给你想放在DelayQueue的东西(内容很丰富,代表你可以利用PriorityQueue的那些构造函数,,,好了,这些东西有点基础的人都自己会还用我说什么!)
    下面说说里面一些我认为比较重要的点,大家编程中留心这些知识点。
    DelayQueue利用PriorityQueue存储自身队列数据,这一点表明他拥有PriorityQueue的很多特性。   1,长度无限长,无offer阻塞; 2,有take阻塞,但是在PriorityQueue基础上又添加了等待线程Thread header,为什么会有这个属性,这就和DelayQueue自身的作用紧密相关了。因为要实现delay效果又要实现并发,必然带来队列存取的同步问题,你可能说不是有lock来保证同步吗?但是别忘了,他们有“取”延时功能,在延时的过程中可能会有其他线程来取队列元素,下给出取元素代码,方便解释
  public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        for (;;) {
            E first = q.peek();
            if (first == null)
                available.await();
            else {
                long delay = first.getDelay(TimeUnit.NANOSECONDS);
                if (delay <= 0)
                    return q.poll();
                else if (leader != null)
                    available.await();
                else {
                    Thread thisThread = Thread.currentThread();
                    leader = thisThread;
                    try {
                        available.awaitNanos(delay);
                    } finally {
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
        if (leader == null && q.peek() != null)
            available.signal();
        lock.unlock();
    }
}
   看到没,在验证队列是否为空时,使用的是PriorityQueue.peek()这个函数很普通并没有对队列进行同步操作,这也导致一个线程在available.awaitNanos(delay);时进入等待状态时,别的线程也有可能调用此函数,而再次进行队列是否为空判定,但是上一个线程并没有取出元素导致这一个线程在使用PriorityQueue.peek())时也会得到队列非空结果,也会进入available.awaitNanos(delay);状态,那么如果没有一些特殊的处理操作肯定会出错,于是这个等待线程标志header就出现了。他很巧妙地实现了这样的功能:会让先运行的“取”线程在等待后先“取”元素,而且是安全取,之后的线程要想“取”必须等待队列非空。这里面还有一点很重要,如果你出于什么目的想要扩展我们的DelayQueue在里面加一些唤醒操作你一定要注意DelayQueue的这一特性,即:我们的所有的等待“取”元素的线程均是由等待“取”线程的队首线程唤醒的!!所以你自己如果随意去使用Condition.signal()去唤醒等待的线程很可能会导致有些“取”线程永远死在那个等待“取”状态(又想多一嘴,由于这个特性,每次“取”并不是真正按着从“小”到“大”的顺序来的,而是部分按着PriorityQueue的方式从“小”到“大”取得)。
    当然你可能有更好的方法实现完全按着从小到大“取”的方法,这个根据你的业务需求,不太严格的情况下这个蛮不错的,如果你实现完全从小到大,我想带来的肯定就是性能问题了
    就到这儿了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值