首页 > 其他分享 >DelayQueue 延迟队列使用

DelayQueue 延迟队列使用

时间:2024-08-16 17:50:34浏览次数:14  
标签:getDelay 队列 Delayed new DelayQueue import public 延迟

一、DelayQueue是什么

  DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。

二、DelayQueue能做什么

 1. 淘宝订单业务:下单之后如果三十分钟之内没有付款就自动取消订单。
 2. 饿了吗订餐通知:下单成功后60s之后给用户发送短信通知。
 3.关闭空闲连接。服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之。
 4.缓存。缓存中的对象,超过了空闲时间,需要从缓存中移出。
 5.任务超时处理。在网络协议滑动窗口请求应答式交互时,处理超时未响应的请求等。

三、实例展示

定义元素类,作为队列的元素

 DelayQueue只能添加(offer/put/add)实现了Delayed接口的对象,意思是说我们不能想往DelayQueue里添加什么就添加什么,不能添加int、也不能添加String进去,必须添加我们自己的实现了Delayed接口的类的对象,来代码:

/**
 *  compareTo 方法必须提供与 getDelay 方法一致的排序
 */
class MyDelayedTask implements Delayed{

    private String name ;
    private long start = System.currentTimeMillis();
    private long time ;

    public MyDelayedTask(String name,long time) {
        this.name = name;
        this.time = time;
    }

    /**
     * 需要实现的接口,获得延迟时间   用过期时间-当前时间
     * @param unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert((start+time) - System.currentTimeMillis(),TimeUnit.MILLISECONDS);
    }

    /**
     * 用于延迟队列内部比较排序   当前时间的延迟时间 - 比较对象的延迟时间
     * @param o
     * @return
     */
    @Override
    public int compareTo(Delayed o) {
        MyDelayedTask o1 = (MyDelayedTask) o;
        return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
    }

    @Override
    public String toString() {
        return "MyDelayedTask{" +
                "name='" + name + '\'' +
                ", time=" + time +
                '}';
    }
}

其中,compareTo 方法 getDelay 方法 就是Delayed接口的方法,我们必须实现,而且按照JAVASE文档,compareTo 方法必须提供与 getDelay 方法一致的排序,也就是说compareTo方法里可以按照getDelay方法的返回值大小排序,即在compareTo方法里比较getDelay方法返回值大小

写main方法测试

定义一个DelayQueue,添加几个元素,while循环获取元素

private static DelayQueue delayQueue  = new DelayQueue();
    public static void main(String[] args) throws InterruptedException {

        new Thread(new Runnable() {
            @Override
            public void run() {

                delayQueue.offer(new MyDelayedTask("task1",10000));
                delayQueue.offer(new MyDelayedTask("task2",3900));
                delayQueue.offer(new MyDelayedTask("task3",1900));
                delayQueue.offer(new MyDelayedTask("task4",5900));
                delayQueue.offer(new MyDelayedTask("task5",6900));
                delayQueue.offer(new MyDelayedTask("task6",7900));
                delayQueue.offer(new MyDelayedTask("task7",4900));

            }
        }).start();

        while (true) {
            Delayed take = delayQueue.take();
            System.out.println(take);
        }
    }

执行结果

DelayQueue属于排序队列,它的特殊之处在于队列的元素必须实现Delayed接口,该接口需要实现compareTo和getDelay方法。

static class Task implements Delayed{
        @Override
                //比较延时,队列里元素的排序依据
        public int compareTo(Delayed o) {
            return 0;
        }
        
        @Override
                //获取剩余时间
        public long getDelay(TimeUnit unit) {
            return 0;
        }
    }

元素进入队列后,先进行排序,然后,只有getDelay也就是剩余时间为0的时候,该元素才有资格被消费者从队列中取出来,所以构造函数一般都有一个时间传入。

另一个例子:

import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * 定时创建
 */
@Slf4j
@Component
public class TestJob implements Runnable {
    @Resource
    private OrderService orderService;
	
    private static final DelayQueue<DelayElement> DELAY_QUEUE = new DelayQueue<>();

    /**
     * 定时扫描
     */
    @XxlJob("testJobHandler")
    public void autoGenerateDoJob() {
        log.info("开始执行扫描");
		DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		// 获取需要添加延时处理的数据
        List<Order> orderList = orderService.getOrderList();
        for (Order one : orderList) {
		    // 获取执行时间
            LocalDateTime time = LocalDateTime.parse(one.getNextTime(), format);
            // 获取延迟时间
            Duration duration = Duration.between(LocalDateTime.now(), time);
            DELAY_QUEUE.put(new PlanJob.DelayElement(duration.toMillis(), order));
            // 更新下次执行时间
            String nextTime = "下次执行时间";
            Order update = new Order();
            update.setId(order.getId());
            update.setNextTime(nextTime);
            orderService.updateById(update);
        }
        log.info("执行扫描结束...");
    }

    @PostConstruct
    public void init() {
        new Thread(this).start();
    }

    @Override
    public void run() {
        synchronized (this) {
            while (true) {
                // 执行延迟任务
                try {
                    // 获取延时数据,执行操作
                    DelayElement take = DELAY_QUEUE.take();
                    Order order = take.getOrder();
					
                    // todo 执行操作

                } catch (Exception e) {
                    log.info("任务失败", e.getMessage(), e);
                }

            }
        }
    }

    @Data
    static class DelayElement implements Delayed {
        long delayTime = System.currentTimeMillis();

        private Order order;

        public DelayElement(long delayTime, Order order) {
            this.delayTime = this.delayTime + delayTime;
            this.order = order;
        }

        @Override
        public long getDelay(@NotNull TimeUnit unit) {
            return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(@NotNull Delayed o) {
            return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
        }
    }
}

原文章地址:
https://www.cnblogs.com/myseries/p/10944211.html

标签:getDelay,队列,Delayed,new,DelayQueue,import,public,延迟
From: https://www.cnblogs.com/1399z3blog/p/18363365

相关文章

  • 第七节:消息队列推拉模式选择、kafak如何提高吞吐量、超时关单和支付成功同时出现咋办
    一.        二.        三.         !作       者:Yaopengfei(姚鹏飞)博客地址:http://www.cnblogs.com/yaopengfei/声     明1:如有错误,欢迎讨论,请勿谩骂^_^。声     明2:原创博客请在转载......
  • BackgroundWorker和BlockingCollection配合实现有消息才发送的队列
    privateBackgroundWorkerm_MessageConsumer=newBackgroundWorker();privateBlockingCollection<string>m_BlockingQueue=newBlockingCollection<string>();构造函数{m_MessageConsumer.DoWork+=M_MessageConsumer_DoWork;m_MessageConsumer.Work......
  • 小X与队列
    题目题目描述小X正和同学们做列队的练习。有\(n\)名同学排成一路纵队,编号为i的同学排在从前往后数第i个位置上,即:初始时的队列为\(1,2,3,...,n\)。接下来小X会发出若干条指令,每条指令形如“请编号为x的同学排到最前面来”。(例如:若当前时刻的队列为\(5,4,3,2......
  • Python中堆、栈、队列之间的区别
    一、队列概念1、队列是只有一端可以进行插入操作,而另一端可以进行删除操作的有序线性存储结构,满足先进先出的约束。2、在计算机科学中,队列是一个集合,其中集合中的实体按顺序保存,集合上的主要(或唯一)操作是向后端位置添加实体,称为入队,前端位置并删除实体,称为出队。这使得队列成为......
  • 高性能无锁队列 Disruptor 核心原理分析及其在i主题业务中的应用
    一、i主题及Disruptor简介i主题是vivo旗下的一款主题商店app,用户可以通过下载主题、壁纸、字体等,实现对手机界面风格的一键更换和自定义。Disruptor是英国外汇交易公司LMAX开发的一个高性能的内存队列(用于系统内部线程间传递消息,不同于RocketMQ、Kafka这种分布式消息......
  • 高性能无锁队列 Disruptor 核心原理分析及其在i主题业务中的应用
    作者:来自vivo互联网服务器团队-LiWanghong本文首先介绍了Disruptor高性能内存队列的基本概念、使用Demo、高性能原理及源码分析,最后通过两个例子介绍了Disruptor在i主题业务中的应用。一、i主题及Disruptor简介i主题是vivo旗下的一款主题商店app,用户可以通过下......
  • 恶补基础知识:Java 栈与队列详解
    @目录前言简介栈Java实现栈的示例代码:栈的主要应用场景包括:队列Java实现队列的示例代码:LinkedList中的add方法和offer方法的区别队列主要应用场景:总结前言请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i、提示:以下是本篇文章正文内容,下面案例可供参考简介使用Java实......
  • 设计模式-延迟加载(Lazy Load)
    概念一个对象,它虽然不包含所需要的所有数据,但是知道怎么获取这些数据。加载一个对象会引起大量相关对象的加载,这样会损害系统的性能。延迟加载会暂时终止这个加载过程。运行机制四种实现延迟加载的方法:延迟初始化(Lazyinitialization)。每次访问属性域都要先检查该域是否......
  • 假设Sigmund Landers在商业街设置了一个提供建议的摊位,顾客可以购买1分钟,2分钟,或3分钟
    /假设SigmundLanders在商业街设置了一个提供建议的摊位,顾客可以购买1分钟,2分钟,或3分钟的建议,为确保交通每个摊位前排队等待的顾客最多10人,用两个队列模拟两个摊位/#include<stdio.h>#include<stdlib.h>#defineMAX_SIZE10typedefstruct{intitems[MAX_SIZE];......
  • 如何保证数据不丢失?(死信队列)
    死信队列1、什么是死信死信通常是消息在特定的场景下表现:消息被拒绝访问消费者发生异常,超过重试次数消息的Expiration过期时间过长或者队列TTL过期时间消息队列到达最大容量maxLength2、什么是死信队列用来存储死信的队列,并且队列中只由死信构成的消息队列是死信队列......