[转] Java 无界阻塞队列 DelayQueue 入门实战

  • 时间:
  • 浏览:0
  • 来源:大发快3_快3手机app下载_大发快3手机app下载

原文出处:http://cmsblogs.com/ 『chenssy

DelayQueue是八个支持延时获取元素的无界阻塞队列。里面的元素全版都有“可延期”的元素,列头的元素是最先“到期”的元素,可能队列里面如此 元素到期,是不到从列头获取元素的,哪怕有元素却说行。也却说说不到在延迟期到时才还可否从队列中取元素。

DelayQueue主要用于八个方面:

  • 缓存:清掉缓存中超时的缓存数据
  • 任务超时外理

DelayQueue

DelayQueue实现的关键主要有如下几个:

  1. 可重入锁ReentrantLock
  2. 用于阻塞和通知的Condition对象
  3. 根据Delay时间排序的优先级队列:PriorityQueue
  4. 用于优化阻塞通知的守护进程元素leader

ReentrantLock、Condition你你你这俩个多对象就不到阐述了,他是实现整个BlockingQueue的核心。PriorityQueue是八个支持优先级守护进程排序的队列(参考【死磕Java并发】-----J.U.C之阻塞队列:PriorityBlockingQueue),leader里面阐述。这里亲戚朋友先来了解Delay,他是实现延时操作的关键。

Delayed

Delayed接口是用来标记那些应该在给定延迟时间以后执行的对象,它定义了八个long getDelay(TimeUnit unit)法律最好的方法,该法律最好的方法返回与此对象相关的的剩余时间。一块儿实现该接口的对象还可否定义八个compareTo 法律最好的方法,该法律最好的方法提供与此接口的 getDelay 法律最好的方法一致的排序。

public interface Delayed extends Comparable<Delayed> {
    long getDelay(TimeUnit unit);
}

如保使用该接口呢?里面说的非常清楚了,实现该接口的getDelay()法律最好的方法,一块儿定义compareTo()法律最好的方法即可。

內部形态学

先看DelayQueue的定义:

    public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
            implements BlockingQueue<E> {
        /** 可重入锁 */
        private final transient ReentrantLock lock = new ReentrantLock();
        /** 支持优先级的BlockingQueue */
        private final PriorityQueue<E> q = new PriorityQueue<E>();
        /** 用于优化阻塞 */
        private Thread leader = null;
        /** Condition */
        private final Condition available = lock.newCondition();

        /**
         * 省略统统代码
         */
    }

想看 DelayQueue的內部形态学 就对里面几个关键点一目了然了,以后 这里有或多或少还可否注意,DelayQueue的元素都还可否继承Delayed接口。一块儿能不还可否从这里初步理清楚DelayQueue內部实现的机制了:以支持优先级无界队列的PriorityQueue作为八个容器,容器里面的元素都应该实现Delayed接口,在每次往优先级队列中上加元素时以元素的过期时间作为排序条件,最先过期的元素倒入优先级最高。

offer()

    public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 向 PriorityQueue中插入元素
            q.offer(e);
            // 可能当前元素的对首元素(优先级最高),leader设置为空,唤醒所有在等待守护进程
            if (q.peek() == e) {
                leader = null;
                available.signal();
            }
            // 无界队列,永远返回true
            return true;
        } finally {
            lock.unlock();
        }
    }

offer(E e)却说往PriorityQueue中上加元素,具体还可否参考(【死磕Java并发】-----J.U.C之阻塞队列:PriorityBlockingQueue)。整个过程还是比较简单,以后 在判断当前元素是不是为对首元素,可能是得话则设置leader=null,这是非常关键的八个步骤,里面阐述。

take()

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                // 对首元素
                E first = q.peek();
                // 对首为空,阻塞,在等待off()操作唤醒
                if (first == null)
                    available.await();
                else {
                    // 获取对首元素的超时时间
                    long delay = first.getDelay(NANOSECONDS);
                    // <=0 表示已过期,出对,return
                    if (delay <= 0)
                        return q.poll();
                    first = null; // don't retain ref while waiting
                    // leader != null 证明有或多或少守护进程在操作,阻塞
                    if (leader != null)
                        available.await();
                    else {
                        // 以后

将leader 设置为当前守护进程,独占
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            // 超时阻塞
                            available.awaitNanos(delay);
                        } finally {
                            // 释放leader
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            // 唤醒阻塞守护进程
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

首先是获取对首元素,可能对首元素的延时时间 delay <= 0 ,则还可否出对了,直接return即可。以后 设置first = null,这里设置为null的主要目的是为了外理内存泄漏。可能 leader != null 则表示当前有守护进程占用,则阻塞,以后 设置leader为当前守护进程,以后 调用awaitNanos()法律最好的方法超时在等待。

first = null

这里为那些可能不设置first = null,则会引起内存泄漏呢?守护进程A到达,列首元素如此 到期,设置leader = 守护进程A,这是守护进程B来了可能leader != null,则会阻塞,守护进程C一样。假如守护进程阻塞完毕了,获取列首元素成功,出列。你你你这俩以后列首元素应该会被回收掉,以后 问题报告 是它还被守护进程B、守护进程C持有着,统统不必回收,这里只八个守护进程,可能有守护进程D、守护进程E...呢?从都是不是限期的不到回收,就会造成内存泄漏。

你你你这俩入队、出对过程和或多或少的阻塞队列如此 很大区别,无非是在出对的以后增加了八个到期时间的判断。一块儿通过leader来减少越多要阻塞。

转载,请保留原文地址,谢谢 ~

猜你喜欢

国内首次网上拍卖波音747:顺丰3.2亿元拍走两架

IT之家11月21日消息波音747可以在网上拍卖了!据报道,国内首次通过网络平台进行司法拍卖三架波音747飞机,最终顺丰航空公司豪掷3.2亿元拍下两架波音747扩充其货机编队。

2020-01-29

2019 年 11月 25 日 随笔档案

摘要:前言开心一刻某人养了一头猪,烦了想放生,另一个猪认识回家的路,放生十几只 它都此人 回来了。一日,你你这个个想了个狠土土办法,开车带着猪转了好多路进山区放生,放生后又

2020-01-29

A. Goljahanpoor数据,A. Goljahanpoor新闻,A. Goljahanpoor视频,A. Goljahanpoor身价

A.GoljahanpoorA.Goljahanpoor俱乐部:TPV谭柏利国籍:芬兰身高:CM位置:中场年龄:24岁体重:KG号码:9号生日:1995-06-07惯用脚:赛季

2020-01-29

多家平台成立共享配送联盟,非诚信配送员将上黑名单

IT之家1月11日消息 昨日,美团外卖、UU跑腿、闪送、邻趣、快服务等多家平台签署成立共享配送联盟。配送员能都可不可不还里能根据人及意愿,承接任一肯能多个平台的订单配送工作,称

2020-01-29

暴徒变身“顾客” 声大夹恶 前线保安成磨心被欺凌

【大公报讯】已持续近两天的连串暴力衝突,多个商场变成暴徒的战场,商场前线保安惨成磨心。香港护卫及物业管理从业员总会早前否认,指暴力衝突事件令前线保安员陷入两难,除了有意味着因妨

2020-01-29