DelayQueue延迟队列-实现缓存

延迟阻塞队列DelayQueue

DelayQueue 是一个支持延时获取元素的阻塞队列,
内部采用优先队列 PriorityQueue 存储元素,
同时元素必须实现 Delayed 接口;在创建元素时可以指定多久才可以从队列中获取当前元素,只有在延迟期满时才能从队列中提取元素。

使用场景

  • 缓存系统:当能够从延迟队列DelayQueue中获取到元素时,说明缓存已经过期
  • 定时任务调度:一分钟后发送短信

基于延迟队列,实现一个缓存系统

延迟队列中添加的元素,实现了Delayed接口

public class CacheItem implements Delayed{
    private long expireTime;

    private long currentTime;

    private String key;

    public String getKey() {
        return key;
    }

    public CacheItem(String key,long expireTime) {
        this.key = key;
        this.expireTime = expireTime;
        this.currentTime = System.currentTimeMillis();
    }

    /**
     * 比较方法,用于排序
     * 过期时间长的放队尾,时间短的放队首
     */
    @Override
    public int compareTo(Delayed o) {
        if(this.getDelay(TimeUnit.MICROSECONDS) > o.getDelay(TimeUnit.MICROSECONDS))
            return 1;
        if(this.getDelay(TimeUnit.MICROSECONDS) > o.getDelay(TimeUnit.MICROSECONDS))
            return -1;
        return 0;
    }

    /**
     * 计算剩余的过期时间
     * 大于0说明没有过期
     */
    @Override
    public long getDelay(TimeUnit unit) {

        return expireTime - unit.MILLISECONDS.toSeconds(System.currentTimeMillis()-currentTime);

    }

}

缓存实现

public class DelayQueueDemo {
    static class Cache implements Runnable{
        private Map<String,String> itemMap = new HashMap<>();

        private DelayQueue<CacheItem> delayQueue = new DelayQueue<>();

        private boolean stop = false;

        // 初始化后就开始检测
        public Cache() {
            new Thread(this).start();
        }

        public void add(String key,String value,long expireTime) {
            CacheItem item = new CacheItem(key,expireTime);
            itemMap.put(key, value);
            delayQueue.add(item);

        }

        public String get(String key) {
            return itemMap.get(key);
        }

        public void shutdown() {
            stop = true;
        }

        // 开启多线程,检测缓存是否过期
        @Override
        public void run() {
            while(!stop) {
                CacheItem item = delayQueue.poll();
                if(item != null) {
                    // 缓存过期
                     itemMap.remove(item.getKey());
                     System.out.println("delete expired key:"+item.getKey());
                }
            }
            System.out.println("Cache stop");
        }
    }

    public static void main(String[] args) throws Exception{
        Cache cache = new Cache();
        cache.add("a", "1", 1);
        cache.add("b", "2", 2);
        cache.add("c", "3", 2);
        cache.add("d", "4", 4);
        cache.add("e", "5", 6);

        while(true) {
            String a = cache.get("a");
            String b = cache.get("b");
            String c = cache.get("c");
            String d = cache.get("d");
            String e = cache.get("e");

            if(a == null && b == null && c == null && d == null && e == null) {
                break;
            }
        }

        TimeUnit.SECONDS.sleep(1);
        cache.shutdown();
    }

}

延迟队列实现原理部分说明

  • 可重入锁 ReentrantLock
  • 优先队列 PriorityQueue

参考连接

原文地址:https://www.cnblogs.com/watertreestar/p/11780249.html

时间: 2024-10-27 18:13:23

DelayQueue延迟队列-实现缓存的相关文章

java延迟队列DelayQueue使用及原理

概述 java延迟队列提供了在指定时间才能获取队列元素的功能,队列头元素是最接近过期的元素.没有过期元素的话,使用poll()方法会返回null值,超时判定是通过getDelay(TimeUnit.NANOSECONDS)方法的返回值小于等于0来判断.延时队列不能存放空元素. 延时队列实现了Iterator接口,但iterator()遍历顺序不保证是元素的实际存放顺序. 队列元素 DelayQueue<E extends Delayed>的队列元素需要实现Delayed接口,该接口类定义如下:

java延迟队列

大多数用到定时执行的功能都是用任务调度来做的,单身当碰到类似订餐业务/购物等这种业务就不好处理了,比如购物的订单功能,在你的订单管理中 有N个订单,当订单超过十分钟未支付的时候自动释放购物车中的商品,订单失效.这种高频率的延迟任务再用任务调度(定时)实现就得不偿失了.推荐用Java延迟队列来实现,DelayQueue是java.util.concurrent中提供的一个类DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象, 其中的对象只能在其到期时

灵感来袭,基于Redis的分布式延迟队列

延迟队列 延迟队列,也就是一定时间之后将消息体放入队列,然后消费者才能正常消费.比如1分钟之后发送短信,发送邮件,检测数据状态等. Redisson Delayed Queue 如果你项目中使用了redisson,那么恭喜你,使用延迟队列将非常的简单. 基于Redis的Redisson分布式延迟队列(Delayed Queue)结构的RDelayedQueue Java对象在实现了RQueue接口的基础上提供了向队列按要求延迟添加项目的功能.该功能可以用来实现消息传送延迟按几何增长或几何衰减的发

RabbitMQ 延迟队列实现订单支付结果异步阶梯性通知

在第三方支付中,例如支付宝.或者微信,对于订单请求,第三方支付系统采用的是消息同步返回.异步通知+主动补偿查询的补偿机制. 由于互联网通信的不可靠性,例如双方网络.服务器.应用等因素的影响,不管是同步返回.异步通知.主动查询报文都可能出现超时无响应.报文丢失等情况,所以像支付业务,对结果的通知一般采用几种方案结合的补偿机制,不能完全依赖某一种机制. 例如一个支付结果的通知,一方面会在支付页面跳转时候返回支付结果(一般只用作前端展示使用,非最终状态),同时会采用后台异步通知机制(有前台.后台通知的

C# RabbitMQ延迟队列功能实战项目演练

一.需求背景 当用户在商城上进行下单支付,我们假设如果8小时没有进行支付,那么就后台自动对该笔交易的状态修改为订单关闭取消,同时给用户发送一份邮件提醒.那么我们应用程序如何实现这样的需求场景呢?在之前的<C# Redis缓存过期实现延迟通知实战演练>分享课程中阿笨最后总结的时候说过Redis Pub/Sub是一种并不可靠地消息机制,他不会做信息的存储,只是在线转发,那么肯定也没有ack确认机制,另外只有订阅段监听时才会转发!我们是否有更好的方式去实现呢?今天给大家分享的比较好的解决方案就是通过

SpringBoot RabbitMQ 延迟队列代码实现

场景 用户下单后,如果30min未支付,则删除该订单,这时候就要可以用延迟队列 准备 利用rabbitmq_delayed_message_exchange插件: 首先下载该插件:https://www.rabbitmq.com/community-plugins.html 然后把该插件放到rabbitmq安装目录plugins下: 进入到sbin目录下,执行"rabbitmq-plugins.bat enable rabbitmq_delayed_message_exchange";

SpringBoot:RabbitMQ 延迟队列

SpringBoot 是为了简化 Spring 应用的创建.运行.调试.部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖就可以轻易的搭建出一个 WEB 工程 初探RabbitMQ消息队列中介绍了RabbitMQ的简单用法,顺带提及了下延迟队列的作用.所谓延时消息就是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进行消费. 延迟队列 延迟队列能做什么? 订单业务: 在电商/点餐

java DelayedQueue延迟队列

代码如下: package com.example.base.concurrent; import java.util.Date; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; import com.example.spring.MyLog; public class MyDelayedQueue { public

如何实现延迟队列

延迟队列的需求各位应该在日常开发的场景中经常碰到.比如: 用户登录之后5分钟给用户做分类推送: 用户多少天未登录给用户做召回推送: 定期检查用户当前退款账单是否被商家处理等等场景. 一般这种场景和定时任务还是有很大的区别,定时任务是你知道任务多久该跑一次或者什么时候只跑一次,这个时间是确定的.延迟队列是当某个事件发生的时候需要延迟多久触发配套事件,引子事件发生的时间不是固定的. 业界目前也有很多实现方案,单机版的方案就不说了,现在也没有哪个公司还是单机版的服务,今天我们一一探讨各种方案的大致实现