延迟队列DelayQueue take() 源码分析

延迟队列DelayQueue take() 源码分析

  • 在工作中使用了延迟队列,对其内部的实现很好奇,于是就研究了一下其运行原理,在这里就介绍一下take()方法的源码

1 take()源码 如下所示

public E take() throws InterruptedException {
        // 加锁的一个动作 保证获取数据的安全性
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                //peek 方法是去头部数据即第一个数据
                E first = q.peek();
                if (first == null)
                    //说明队列为空 调用condition.await()方法,会使得当前线程释放lock然后加入到等待队列中
                    available.await();
                else {
                    //如果第一个数据不为空 获取消息体的延迟时间(getDelay() 会在消息体内重写 自定义添加延迟时间)
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        //如果延迟时间 小于等于0 说明已经达到了延迟时间 调用poll方法返回消息体
                        return q.poll();
                    //如果延迟时间不为空的话 说明还需要等待一段时间 此时重新循环 所以讲frist置为空
                    first = null; 
                    if (leader != null)
                        //这里用到了Leader/Followers模式 有兴趣的话可以去百度一下这个模式
                        //如果leader 不为空 说明已经有线程在监听 即有线程在优先获取队列的首元素
                        //释放当前线程获取的锁 加入到等待队列中 即 当前线程变成了Followers
                        available.await();
                    else {
                        //如果没有leader 说明没有线程在监听(没有线程在优先获取队列的首元素)
                        // 将当前线程置为leader线程 
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            //让当前线程最长等待 delay 时间 等待
                            available.awaitNanos(delay);
                        } finally {
                            //释放leader权限
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            // 如果leader 为空 且 队列中有数据 说明没有其他线程在在等待 
            if (leader == null && q.peek() != null)
                //唤醒睡眠的线程
                available.signal();
            //释放锁
            lock.unlock();
        }
    }

注意事项:
一开始不明白为什么将frist置为NULL,后面在网上找了相关的资料了解到,如果不讲first置为Null会导致内存泄漏的问题,具体原因如下所示:

  • 如果不将first置为Null,线程A到达,队首元素还没到出列时间,设置线程A = leader
  • 线程B来了因为leader不为空 则会阻塞,后续线程一样。
  • 假如线程A阻塞完毕之后获取列首元素成功出列,这个时候列首元素应该被回收,但是它还被线程B C ...所持有一直不会被回收就导致了内存泄漏(gc一直无法回收frist这个对象)这个情况。

转载于:https://www.cnblogs.com/karlMa/p/11313330.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值