使用Java延时队列DelayQueue实现订单延时处理

DelayQueue简单介绍

DelayQueue:一个使用优先级队列实现的无界阻塞队列。

支持延时获取的元素的阻塞队列,元素必须要实现Delayed接口。

适用场景:实现自己的缓存系统,订单到期,限时支付等等。

具体代码会有注释,很好理解!

这里我们模拟一个订单延时处理的demo

首先我们定义一个订单实体类

/**
 * 订单实体类
 * @author James Lee
 *
 */
public class Order {
	// 订单编号
	private String orderId;
	// 订单金额
	private Double orderMoney;
	// 省略get、set等方法

}

创建存到队列里的元素

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
 * 存到队列里的元素
 * 支持延时获取的元素的阻塞队列,元素必须要实现Delayed接口。
 * 根据订单有效时间作为队列的优先级
 * @param <T>
 */
public class ItemVo<T> implements Delayed{
	// 到期时间 单位:ms
	private long activeTime;
	// 订单实体(使用泛型是因为后续扩展其他业务共用此业务类)
	private T data;
	
	public ItemVo(long activeTime, T data) {
		super();
		// 将传入的时间转换为超时的时刻
		this.activeTime = TimeUnit.NANOSECONDS.convert(activeTime, TimeUnit.MILLISECONDS) 
				+ System.nanoTime();
		this.data = data;
	}

	public long getActiveTime() {
		return activeTime;
	}
	public T getData() {
		return data;
	}

	// 按照剩余时间进行排序
	@Override
	public int compareTo(Delayed o) {
		// 订单剩余时间-当前传入的时间= 实际剩余时间(单位纳秒)
		long d = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
		// 根据剩余时间判断等于0 返回1 不等于0 
		// 有可能大于0 有可能小于0  大于0返回1  小于返回-1
		return (d == 0) ? 0 : ((d > 0) ? 1 : -1);
	}

	// 获取剩余时间
	@Override
	public long getDelay(TimeUnit unit) {
		// 剩余时间= 到期时间-当前系统时间,系统一般是纳秒级的,所以这里做一次转换
		long d = unit.convert(activeTime-System.nanoTime(), TimeUnit.NANOSECONDS);
		return d;
	}

}

创建订单生成类

import java.util.concurrent.DelayQueue;

/**
 * 模拟订单插入的功能
 */
public class PutOrder implements Runnable {
	
	// 使用DelayQueue:一个使用优先级队列实现的无界阻塞队列。
	private DelayQueue<ItemVo<Order>> queue;
	
	public PutOrder(DelayQueue<ItemVo<Order>> queue) {
		super();
		this.queue = queue;
	}

	@Override
	public void run() {
		/**
		 * 这里模拟淘宝、京东、苏宁的订单,淘宝是5秒到期,京东是10秒到期,苏宁是15秒到期
		 */
		// 淘宝订单插入
		Order tbOrder = new Order("tb001", 9.9);
		ItemVo<Order> itemVoTb = new ItemVo<Order>(5000, tbOrder);
		queue.offer(itemVoTb);
		System.out.println("淘宝订单5秒后过期:" + tbOrder.getOrderId());
		
		// 京东订单插入
		Order jdOrder = new Order("jd002", 19.9);
		ItemVo<Order> itemVoJd = new ItemVo<Order>(10000, jdOrder);
		queue.offer(itemVoJd);
		System.out.println("京东订单10秒后过期:" + jdOrder.getOrderId());
		
		// 苏宁订单插入
		Order snOrder = new Order("sn003", 29.9);
		ItemVo<Order> itemVoSn = new ItemVo<Order>(15000, snOrder);
		queue.offer(itemVoSn);
		System.out.println("苏宁订单15秒后过期:" + tbOrder.getOrderId());

	}
}

创建订单过期取出类

import java.util.concurrent.DelayQueue;
/**
 * 取出到期的订单的功能
 */
public class FetchOrder implements Runnable{
	
	// 使用DelayQueue:一个使用优先级队列实现的无界阻塞队列。
	private DelayQueue<ItemVo<Order>> queue;
	
	public FetchOrder(DelayQueue<ItemVo<Order>> queue) {
		super();
		this.queue = queue;
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				// 使用DelayQueue的take方法获取当前队列里的元素(take方法是阻塞方法,如果队列里有值则取出,否则一直阻塞)
				ItemVo<Order> itemVo = queue.take();
				// 获取元素的实体对象,保险起见做一次强制转型
				Order order = (Order)itemVo.getData();
				System.out.println("订单:" + order.getOrderId()+ " 已过期!已从订单队列里剔除!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}

}

测试代码

import java.util.concurrent.DelayQueue;

/**
 * 测试
 */
public class Test {
	public static void main(String[] args) throws InterruptedException {
		DelayQueue<ItemVo<Order>> queue = new DelayQueue<ItemVo<Order>>();
		// 插入订单
		new Thread(new PutOrder(queue)).start();
		// 取出过期订单的线程
		new Thread(new FetchOrder(queue)).start();
		
		// 为了看到效果,这里没个一秒打印一次时间,一共15秒,打印15次。
		for (int i = 1; i <= 15; i++) {
			Thread.sleep(1000);
			System.out.println("========================="+ i);
		}
	}
}

测试结果

淘宝订单5秒后过期:tb001
京东订单10秒后过期:jd002
苏宁订单15秒后过期:tb001
=========================1
=========================2
=========================3
=========================4
订单:tb001 已过期!已从订单队列里剔除!
=========================5
=========================6
=========================7
=========================8
=========================9
订单:jd002 已过期!已从订单队列里剔除!
=========================10
=========================11
=========================12
=========================13
=========================14
订单:sn003 已过期!已从订单队列里剔除!
=========================15

结果分析

 

Java中的DelayQueue是一个特殊的队列,它只允许在指定的延迟时间之后才能从队列中取出元素。可以使用DelayQueue实现一些延迟任务的功能,例如任务调度、缓存过期等。 DelayQueue基于PriorityQueue实现,但是它的元素必须实现Delayed接口,Delayed接口中定义了一个getDelay()方法,返回元素的延迟时间。 当从DelayQueue中取出元素时,如果该元素的延迟时间还没有到达,则该元素会被重新加入队列中,直到延迟时间到达。 以下是一个简单的使用DelayQueue的例子: ```java import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class DelayQueueExample { public static void main(String[] args) throws InterruptedException { DelayQueue<DelayedElement> delayQueue = new DelayQueue<DelayedElement>(); delayQueue.add(new DelayedElement("element1", 2000)); delayQueue.add(new DelayedElement("element2", 5000)); delayQueue.add(new DelayedElement("element3", 1000)); while (!delayQueue.isEmpty()) { DelayedElement element = delayQueue.take(); System.out.println("Taking element: " + element); } } static class DelayedElement implements Delayed { private String name; private long delayTime; public DelayedElement(String name, long delayTime) { this.name = name; this.delayTime = System.currentTimeMillis() + delayTime; } @Override public long getDelay(TimeUnit unit) { long diff = delayTime - System.currentTimeMillis(); return unit.convert(diff, TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { if (this.delayTime < ((DelayedElement) o).delayTime) { return -1; } if (this.delayTime > ((DelayedElement) o).delayTime) { return 1; } return 0; } @Override public String toString() { return "DelayedElement{" + "name='" + name + '\'' + ", delayTime=" + delayTime + '}'; } } } ``` 在上面的例子中,我们创建了一个DelayQueue,并向其中添加了三个DelayedElement元素。每个元素都有一个延迟时间,分别为2秒、5秒和1秒。 在主线程中,我们不断地从DelayQueue中取出元素,直到队列为空。当元素的延迟时间还没有到达时,它会被重新加入队列中,直到延迟时间到达。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值