使用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 
 */
public class ItemVo 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> queue;
	
	public PutOrder(DelayQueue> queue) {
		super();
		this.queue = queue;
	}

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

	}
}

创建订单过期取出类

import java.util.concurrent.DelayQueue;
/**
 * 取出到期的订单的功能
 */
public class FetchOrder implements Runnable{
	
	// 使用DelayQueue:一个使用优先级队列实现的无界阻塞队列。
	private DelayQueue> queue;
	
	public FetchOrder(DelayQueue> queue) {
		super();
		this.queue = queue;
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				// 使用DelayQueue的take方法获取当前队列里的元素(take方法是阻塞方法,如果队列里有值则取出,否则一直阻塞)
				ItemVo 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> queue = new DelayQueue>();
		// 插入订单
		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实现订单延时处理_第1张图片

 

你可能感兴趣的:(java基础笔记)