推荐一款高效的处理延迟任务神器

作者:微信小助手

发布时间:2020-02-12T16:24:28

点击▲关注 “爪哇笔记”   给公众号标星置顶

更多精彩 第一时间直达

时间轮算法

时间轮是一种高效、低延迟的调度数据结构。其在Linux内核中广泛使用,是Linux内核定时器的实现方法和基础之一。按使用场景,大致可以分为两种时间轮:原始时间轮和分层时间轮。分层时间轮是原始时间轮的升级版本,来应对时间“槽”数量比较大的情况,对内存和精度都有很高要求的情况。延迟任务的场景一般只需要用到原始时间轮就可以了。

代码案例

推荐使用Netty提供的HashedWheelTimer工具类来实现延迟任务。

引入依赖:

 
  1. <dependency>

  2. <groupId>io.netty</groupId>

  3. <artifactId>netty-common</artifactId>

  4. <version>4.1.23.Final</version>

  5. </dependency>

红包过期队列信息:

 
  1. /**

  2. * 红包过期队列信息

  3. */

  4. public class RedPacketTimerTask implements TimerTask {


  5. private static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");


  6. /**

  7. * 红包 ID

  8. */

  9. private final long redPacketId;


  10. /**

  11. * 创建时间戳

  12. */

  13. private final long timestamp;


  14. public RedPacketTimerTask(long redPacketId) {

  15. this.redPacketId = redPacketId;

  16. this.timestamp = System.currentTimeMillis();

  17. }


  18. @Override

  19. public void run(Timeout timeout) {

  20. //异步处理任务

  21. System.out.println(String.format("任务执行时间:%s,红包创建时间:%s,红包ID:%s",

  22. LocalDateTime.now().format(F), LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()).format(F), redPacketId));

  23. }

  24. }

测试用例:

 
  1. /**

  2. * 基于 netty 的时间轮算法 HashedWheelTimer 实现的延迟任务

  3. */

  4. public class RedPacketHashedWheelTimer {


  5. private static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");


  6. public static void main(String[] args) throws Exception {

  7. ThreadFactory factory = r -> {

  8. Thread thread = new Thread(r);

  9. thread.setDaemon(true);

  10. thread.setName("RedPacketHashedWheelTimerWorker");

  11. return thread;

  12. };

  13. /**

  14. * @param tickDuration - 每tick一次的时间间隔

  15. * @param unit - tickDuration 的时间单位

  16. * @param ticksPerWheel - 时间轮中的槽数

  17. * @param leakDetection - 检查内存溢出

  18. */

  19. Timer timer = new HashedWheelTimer(factory, 1,

  20. TimeUnit.SECONDS, 100,true);

  21. System.out.println(String.format("开始任务时间:%s",LocalDateTime.now().format(F)));

  22. for(int i=1;i<10;i++){

  23. TimerTask timerTask = new RedPacketTimerTask(i);

  24. timer.newTimeout(timerTask, i, TimeUnit.SECONDS);

  25. }

  26. Thread.sleep(Integer.MAX_VALUE);

  27. }

  28. }

打印任务执行日志:

 
  1. 开始任务时间:2020-02-12 15:22:23.404

  2. 任务执行时间:2020-02-12 15:22:25.410,红包创建时间:2020-02-12