延迟任务的实现总结.docxVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
延迟任务的实现总结 上一篇写了使用 RabbitMQ 来实现延迟任务的实现,其实实现延迟任务的方式有很多,各有利弊,有单机和分布式 的。在这里做一个总结,在遇到这类问题的时候希望给大家 一个参考和思路。 延迟任务有别于定式任务,定式任务往往是固定周期的,有明确的触发时间。而延迟任务一般没有 固定的开始时间,它常常是由一个事件触发的,而在这个事 件触发之后的一段时间内触发另一个事件。延迟任务相关的 业务场景如下: 场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时。 场景二:订单下单之后 30 分钟后,如果用户没有付钱,则系统自动取消订单。 下面我们来探讨一些方案,其实这些方案没有好坏之分,和系统架构一样,只有最适合。对于数 据量较小的情况下,任意一种方案都可行,考虑的是简单明 了和开发速度,尽量避免把系统搞复杂了。而对于数据量较 大的情况下,就需要有一些选择,并不是所有的方案都适合 了。 1. 数据库轮询 这是比较常见的一种方式,所有的订单或者所有的命令一般都会存储在数据库中。我们会起一个 线程去扫数据库或者一个数据库定时 Job,找到那些超时的数据,直接更新状态,或者拿出来执行一些操作。这种方式 很简单,不会引入其他的技术,开发周期短。 如果数据量 比较大,千万级甚至更多,插入频率很高的话,上面的方式 在性能上会出现一些问题,查找和更新对会占用很多时间, 轮询频率高的话甚至会影响数据入库。一种可以尝试的方式 就是使用类似TBSchedule 或Elastic-Job 这样的分布式的任务调度加上数据分片功能,把需要判断的数据分到不同的机 器上执行。 如果数据量进一步增大,那扫数据库肯定就不行了。另一方面,对于订单这类数据,我们也许会遇到分库 分表,那上述方案就会变得过于复杂,得不偿失。 2. JDK 延迟队列 Java 中的 DelayQueue 位于 java.util.concurrent 包下,作为单机实现,它很好的实现了延迟一段时间后触发 事件的需求。由于是线程安全的它可以有多个消费者和多个 生产者,从而在某些情况下可以提升性能。DelayQueue 本质是封装了一个 PriorityQueue,使之线程安全,加上Delay 功能,也就是说,消费者线程只能在队列中的消息“过期”之后才能返回数据获取到消息,不然只能获取到 null。 之所以要用到 PriorityQueue,主要是需要排序。也许后插入的消息需要比队列中的其他消息提前触发,那么这个后插入的消息 就需要最先被消费者获取,这就需要排序功能。PriorityQueue 内部使用最小堆来实现排序队列。队首的,最先被消费者拿到的就是最小的那个。使用最小堆让队列在数 据量较大的时候比较有优势。使用最小堆来实现优先级队列 主要是因为最小堆在插入和获取时,时间复杂度相对都比较 好,都是 O(logN)。 下面例子实现了未来某个时间要触发的消息。我把这些消息放在 DelayQueue 中,当消息的触发时间到,消费者就能拿到消息,并且消费,实现处理方法。示 例代码: /* * 定义放在延迟队列中的对象,需要实现 Delayed 接口 */ public class DelayedTask implements Delayed { private int _expireInSecond = 0; public DelayedTask(int delaySecond) { Calendar cal = Calendar.getInstance(); cal.add(Calendar.SECOND, delaySecond); _expireInSecond = (int) (cal.getTimeInMillis() / 1000); } public int compareTo(Delayed o) { long d = (getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS)); return (d == 0) ? 0 : ((d lt; 0) ? -1 : 1); } public long getDelay(TimeUnit unit) { // TODO Auto-generated method stub 1000); } } Calendar cal = Calendar.getInstance(); return _expireInSecond - (cal.getTimeInMillis() / 下面定义了三个延迟任务,分别是 10 秒,5 秒和 15 秒。依次入队列,期望 5 秒钟后,5 秒的消息先被获取到,然后每个 5 秒钟,依次获取到 10 秒

文档评论(0)

hao187 + 关注
官方认证
文档贡献者

该用户很懒,什么也没介绍

认证主体武汉豪锦宏商务信息咨询服务有限公司
IP属地上海
统一社会信用代码/组织机构代码
91420100MA4F3KHG8Q

1亿VIP精品文档

相关文档