Java延迟队列 DelayQueue讲解


前言

在项目中,下单业务下单之后,如果30分钟之内没有付款就自动取消付款,就需要用到延迟队列,来实现取消功能


一、DelayQueue是什么?

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

二、使用步骤

1.创建一个Delayed接口的实现类,该元素要放入到DealyQueue队列中

代码如下(示例):

import com.google.common.primitives.Ints;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public abstract class Task implements Delayed, Runnable{
    private String id = "";
    private long start = 0;

    public Task(String id, long delayInMilliseconds){
        this.id = id;
        this.start = System.currentTimeMillis() + delayInMilliseconds;
    }

    public String getId() {
        return id;
    }

	//获取剩余的时间,为0获取负数时取出
    //TimeUnit.NANOSECONDS 毫微妙
    @Override
    public long getDelay(TimeUnit unit) {
        long diff = this.start - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }

	// 排序
    @Override
    public int compareTo(Delayed o) {
        return Ints.saturatedCast(this.start - ((Task) o).start);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null) return false;
        if (!(o instanceof Task)) {
            return false;
        }
        Task t = (Task)o;
        return this.id.equals(t.getId());
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

2.创建DelayQueue 的工具类

代码如下(示例):

data = pd.read_csv(
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Executors;

@Component
public class TaskService {
    private TaskService taskService;
    private DelayQueue<Task> delayQueue =  new DelayQueue<Task>();

    @PostConstruct 
    private void init() {
        taskService = this;

		// 单个线程的线程池 可手动创建
        Executors.newSingleThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Task task = delayQueue.take();
                        task.run();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    public void addTask(Task task){
        if(delayQueue.contains(task)){
            return;
        }
        delayQueue.add(task);
    }

    public void removeTask(Task task){
        delayQueue.remove(task);
    }

3.处理 我们的业务需求 类

public class OrderUnpaidTask extends Task {
    private final Log logger = LogFactory.getLog(OrderUnpaidTask.class);
    private int orderId = -1;

	// 订单id , 延迟时间 
    public OrderUnpaidTask(Integer orderId, long delayInMilliseconds){
        super("OrderUnpaidTask-" + orderId, delayInMilliseconds);
        this.orderId = orderId;
    }

    public OrderUnpaidTask(Integer orderId){
        super("OrderUnpaidTask-" + orderId, 60 * 60 * 1000);
        this.orderId = orderId;
    }

    @Override
    public void run() {
        logger.info("系统开始处理延时任务---订单超时未付款---" + this.orderId);

        // 业务处理

        logger.info("系统结束处理延时任务---订单超时未付款---" + this.orderId);
    }
}

4.使用

	@Autowired
    private TaskService taskService;
	
	public void addTask() {

		// 订单支付超期任务
    	taskService.addTask(new OrderUnpaidTask(orderId));
	}
	

5. 自启动加入队列

因为这些队列是保存在内存中的,当我们关闭程序或重启程序后队列中的值都会消失,所以我们要在程序启动时将数据添加入队列中

SpringBoot给我们提供了两个接口来帮助我们实现这种需求。这两个接口分别为CommandLineRunner和ApplicationRunner。他们的执行时机为容器启动完成的时候

@Component
public class TaskStartupRunner implements ApplicationRunner {

    @Autowired
    private LitemallOrderService orderService;
    @Autowired
    private TaskService taskService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
    	// 查询出所有 未支付的订单
        List<LitemallOrder> orderList = orderService.queryUnpaid(SystemConfig.getOrderUnpaid());
        for(LitemallOrder order : orderList){
            LocalDateTime add = order.getAddTime();
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime expire =  add.plusMinutes(SystemConfig.getOrderUnpaid());
            if(expire.isBefore(now)) {
                // 已经过期,则加入延迟队列 立即执行
                taskService.addTask(new OrderUnpaidTask(order.getId(), 0));
            }
            else{
                // 还没过期,则加入延迟队列
                long delay = ChronoUnit.MILLIS.between(now, expire);
                taskService.addTask(new OrderUnpaidTask(order.getId(), delay));
            }
        }
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以通过以下步骤创建 Java 延迟队列: 1. 导入延迟队列所需的类: ```java import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; ``` 2. 创建 Delayed 接口的实现类,该类的对象将被存储在延迟队列中。例如: ```java class DelayedTask implements Delayed { private String name; private long executeTime; public DelayedTask(String name, long delay) { this.name = name; this.executeTime = System.currentTimeMillis() + delay; } @Override public long getDelay(TimeUnit unit) { long diff = executeTime - System.currentTimeMillis(); return unit.convert(diff, TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { long diff = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS); return Long.compare(diff, 0); } @Override public String toString() { return "DelayedTask{" + "name='" + name + '\'' + ", executeTime=" + executeTime + '}'; } } ``` 3. 创建 DelayQueue 实例,将 Delayed 对象添加到队列中: ```java DelayQueue<DelayedTask> delayQueue = new DelayQueue<>(); delayQueue.put(new DelayedTask("task1", 1000)); // 添加延迟 1s 的任务 delayQueue.put(new DelayedTask("task2", 2000)); // 添加延迟 2s 的任务 ``` 4. 使用 take() 方法获取延迟时间到的 Delayed 对象: ```java while (true) { DelayedTask task = delayQueue.take(); System.out.println(task); } ``` 以上就是创建 Java 延迟队列的基本步骤。你可以根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值