zoukankan      html  css  js  c++  java
  • 延迟队列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这个对象)这个情况。
  • 相关阅读:
    Ubuntu下安装mysql
    MySQL聚集索引与非聚集索引
    mysql索引的简单介绍
    Hive数据导入与导出
    hive的基本操作
    hive的数据模型
    29 ArcMap许可服务器点击授权后无法进入下一步
    28 ArcMap 运行特别慢怎么办
    27 ArcMap加载天地图服务一片空白怎么办
    26 Arcpy跳坑系列——ExportToPNG
  • 原文地址:https://www.cnblogs.com/karlMa/p/11313330.html
Copyright © 2011-2022 走看看