首先我们了解是时间轮的算法:
时间轮:就像上面的时间盘,里面有8个格子组成一个时间轮,如果每个格子代表的时间为1s,那么一圈的就代表8秒。
加入我们将延迟任务加入时间轮的时间为时间轮中0秒的位置,延迟5秒执行,那就是说当转到6个格子的时候就会开始执行定时任务,如果超过8秒,需要延时20秒的,那就需要转多个圈。按以上实例,需要转2圈+4个格子,那就那就是转了2圈后在5标号的格子开始。
首先我们看下netty 中的时间轮类
Netty构建延时队列主要用HashedWheelTimer,HashedWheelTimer底层数据结构依然是使用DelayedQueue,只是采用时间轮的算法来实现。
首先来看一下构造方法
该类提供了多种构造方法。
主要构造方法参数
ThreadFactory threadFactory 表示用于生成工作线程,一般采用线程池;
long tickDuration 每格的时间间隔,默认100ms;
TimeUnit unit 时间单位
int ticksPerWheel 一圈的总格子数,默认512
下面我们看下他的默认无参构造方法
实现代码
1、定义订单实体类
@Data
public class Order {
/**
* 订单编号
*/
private String orderNo;
/**
* 价格(元)
*/
private BigDecimal price;
/**
* 商品数量
*/
private int prodductNum;
/**
* 总金额
*/
private BigDecimal totalAmount;
/**
* 创建时间
*/
private Date createTime;
}
定义任务实体类
public class DelayTask implements TimerTask {
private Order order;
private boolean expiredFlag;
public DelayTask(Order order, boolean expiredFlag) {
this.order = order;
this.expiredFlag = expiredFlag;
}
@Override
public void run(Timeout timeout) throws Exception {
//此处编写执行订单超时状态的逻辑代码
final String nowformat = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
final long diff = (new Date().getTime() - order.getCreateTime().getTime()) / 1000;
System.out.println(order.getOrderNo() + "订单已经超时了" + "失效时间" +diff+"秒" );
}
}
定时时间轮,执行任务
public class OrderDelayTask {
/**
* 定义时间轮对象,每个延迟任务一个
*/
private static final Timer wheelTimer = new HashedWheelTimer();
/**
* @param order 订单信息
* @param expiredTime 超时时间
* @param unit 超时单位
*/
public static void executeDelayTask(Order order, int expiredTime, TimeUnit unit) {
//创建订单任务
final DelayTask delayTask = new DelayTask(order, true);
//执行延迟队列
wheelTimer.newTimeout(delayTask, expiredTime, unit);
}
}
定义测试方法
public static void main(String[] args) throws InterruptedException {
Order order = null;
for (int i = 0; i < 10; i++) {
// Thread.sleep(1000);
order = new Order();
order.setOrderNo(new Snowflake().nextIdStr());
order.setCreateTime(new Date());
OrderDelayTask.executeDelayTask(order, 10, TimeUnit.SECONDS);
}
}
实现结果截图
有点:代码实现简单
缺点:对内存消耗较大,集群部署不友好。