延时队列,第一他是个队列,所以具有对列功能第二就是延时,这就是延时对列,功能也就是将任务放在该延时对列中,只有到了延时时刻才能从该延时对列中获取任务否则获取不到……

应用场景比较多,比如延时1分钟发短信,延时1分钟再次执行等,下面先看看延时队列demo之后再看延时队列在项目中的使用:

简单的延时队列要有三部分:第一实现了Delayed接口的消息体、第二消费消息的消费者、第三存放消息的延时队列,那下面就来看看延时队列demo。

一、消息体

  1. package com.delqueue;
  2. import java.util.concurrent.Delayed;
  3. import java.util.concurrent.TimeUnit;
  4. /**
  5. * 消息体定义 实现Delayed接口就是实现两个方法即compareTo 和 getDelay最重要的就是getDelay方法,这个方法用来判断是否到期……
  6. *
  7. * @author whd
  8. * @date 2017年9月24日 下午8:57:14
  9. */
  10. public class Message implements Delayed {
  11. private int id;
  12. private String body; // 消息内容
  13. private long excuteTime;// 延迟时长,这个是必须的属性因为要按照这个判断延时时长。
  14. public int getId() {
  15. return id;
  16. }
  17. public String getBody() {
  18. return body;
  19. }
  20. public long getExcuteTime() {
  21. return excuteTime;
  22. }
  23. public Message(int id, String body, long delayTime) {
  24. this.id = id;
  25. this.body = body;
  26. this.excuteTime = TimeUnit.NANOSECONDS.convert(delayTime, TimeUnit.MILLISECONDS) + System.nanoTime();
  27. }
  28. // 自定义实现比较方法返回 1 0 -1三个参数
  29. @Override
  30. public int compareTo(Delayed delayed) {
  31. Message msg = (Message) delayed;
  32. return Integer.valueOf(this.id) > Integer.valueOf(msg.id) ? 1
  33. : (Integer.valueOf(this.id) < Integer.valueOf(msg.id) ? -1 : 0);
  34. }
  35. // 延迟任务是否到时就是按照这个方法判断如果返回的是负数则说明到期否则还没到期
  36. @Override
  37. public long getDelay(TimeUnit unit) {
  38. return unit.convert(this.excuteTime - System.nanoTime(), TimeUnit.NANOSECONDS);
  39. }
  40. }

二、消息消费者

  1. package com.delqueue;
  2. import java.util.concurrent.DelayQueue;
  3. public class Consumer implements Runnable {
  4. // 延时队列 ,消费者从其中获取消息进行消费
  5. private DelayQueue<Message> queue;
  6. public Consumer(DelayQueue<Message> queue) {
  7. this.queue = queue;
  8. }
  9. @Override
  10. public void run() {
  11. while (true) {
  12. try {
  13. Message take = queue.take();
  14. System.out.println("消费消息id:" + take.getId() + " 消息体:" + take.getBody());
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. }
  20. }

三、延时队列

  1. package com.delqueue;
  2. import java.util.concurrent.DelayQueue;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. public class DelayQueueTest {
  6. public static void main(String[] args) {
  7. // 创建延时队列
  8. DelayQueue<Message> queue = new DelayQueue<Message>();
  9. // 添加延时消息,m1 延时3s
  10. Message m1 = new Message(1, "world", 3000);
  11. // 添加延时消息,m2 延时10s
  12. Message m2 = new Message(2, "hello", 10000);
  13. //将延时消息放到延时队列中
  14. queue.offer(m2);
  15. queue.offer(m1);
  16. // 启动消费线程 消费添加到延时队列中的消息,前提是任务到了延期时间
  17. ExecutorService exec = Executors.newFixedThreadPool(1);
  18. exec.execute(new Consumer(queue));
  19. exec.shutdown();
  20. }
  21. }

将消息体放入延迟队列中,在启动消费者线程去消费延迟队列中的消息,如果延迟队列中的消息到了延迟时间则可以从中取出消息否则无法取出消息也就无法消费。

这就是延迟队列demo,下面我们来说说在真实环境下的使用。

使用场景描述:

在打车软件中对订单进行派单的流程,当有订单的时候给该订单筛选司机,然后给当订单绑定司机,但是有时运气没那么好,订单进来后第一次没有筛选到合适的司机,但我们也不能就此结束派单,而是将该订单的信息放到延时队列中过个2秒钟在进行一次,其实这个2秒钟就是一个延迟,所以这里我们就可以使用延时队列来实现……

下面看看简单的流程图:

下面来看看具体代码实现:

在项目中有如下几个类:第一 、任务类   第二、按照任务类组装的消息体类  第三、延迟队列管理类

任务类即执行筛选司机、绑单、push消息的任务类

  1. package com.test.delayqueue;
  2. /**
  3. * 具体执行相关业务的业务类
  4. * @author whd
  5. * @date 2017年9月25日 上午12:49:32
  6. */
  7. public class DelayOrderWorker  implements Runnable {
  8. @Override
  9. public void run() {
  10. // TODO Auto-generated method stub
  11. //相关业务逻辑处理
  12. System.out.println(Thread.currentThread().getName()+" do something ……");
  13. }
  14. }

消息体类,在延时队列中这个实现了Delayed接口的消息类是比不可少的,实现接口时有一个getDelay(TimeUnit unit)方法,这个方法就是判断是否到期的

这里定义的是一个泛型类,所以可以将我们上面的任务类作为其中的task,这样就将任务类分装成了一个消息体

  1. package com.test.delayqueue;
  2. import java.util.concurrent.Delayed;
  3. import java.util.concurrent.TimeUnit;
  4. /**
  5. * 延时队列中的消息体将任务封装为消息体
  6. *
  7. * @author whd
  8. * @date 2017年9月25日 上午12:48:30
  9. * @param <T>
  10. */
  11. public class DelayOrderTask<T extends Runnable> implements Delayed {
  12. private final long time;
  13. private final T task; // 任务类,也就是之前定义的任务类
  14. /**
  15. * @param timeout
  16. *            超时时间(秒)
  17. * @param task
  18. *            任务
  19. */
  20. public DelayOrderTask(long timeout, T task) {
  21. this.time = System.nanoTime() + timeout;
  22. this.task = task;
  23. }
  24. @Override
  25. public int compareTo(Delayed o) {
  26. // TODO Auto-generated method stub
  27. DelayOrderTask other = (DelayOrderTask) o;
  28. long diff = time - other.time;
  29. if (diff > 0) {
  30. return 1;
  31. } else if (diff < 0) {
  32. return -1;
  33. } else {
  34. return 0;
  35. }
  36. }
  37. @Override
  38. public long getDelay(TimeUnit unit) {
  39. // TODO Auto-generated method stub
  40. return unit.convert(this.time - System.nanoTime(), TimeUnit.NANOSECONDS);
  41. }
  42. @Override
  43. public int hashCode() {
  44. return task.hashCode();
  45. }
  46. public T getTask() {
  47. return task;
  48. }
  49. }

延时队列管理类,这个类主要就是将任务类封装成消息并并添加到延时队列中,以及轮询延时队列从中取出到时的消息体,在获取任务类放到线程池中执行任务

  1. package com.test.delayqueue;
  2. import java.util.Map;
  3. import java.util.concurrent.DelayQueue;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.TimeUnit;
  7. import java.util.concurrent.atomic.AtomicLong;
  8. /**
  9. * 延时队列管理类,用来添加任务、执行任务
  10. *
  11. * @author whd
  12. * @date 2017年9月25日 上午12:44:59
  13. */
  14. public class DelayOrderQueueManager {
  15. private final static int DEFAULT_THREAD_NUM = 5;
  16. private static int thread_num = DEFAULT_THREAD_NUM;
  17. // 固定大小线程池
  18. private ExecutorService executor;
  19. // 守护线程
  20. private Thread daemonThread;
  21. // 延时队列
  22. private DelayQueue<DelayOrderTask<?>> delayQueue;
  23. private static final AtomicLong atomic = new AtomicLong(0);
  24. private final long n = 1;
  25. private static DelayOrderQueueManager instance = new DelayOrderQueueManager();
  26. private DelayOrderQueueManager() {
  27. executor = Executors.newFixedThreadPool(thread_num);
  28. delayQueue = new DelayQueue<>();
  29. init();
  30. }
  31. public static DelayOrderQueueManager getInstance() {
  32. return instance;
  33. }
  34. /**
  35. * 初始化
  36. */
  37. public void init() {
  38. daemonThread = new Thread(() -> {
  39. execute();
  40. });
  41. daemonThread.setName("DelayQueueMonitor");
  42. daemonThread.start();
  43. }
  44. private void execute() {
  45. while (true) {
  46. Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
  47. System.out.println("当前存活线程数量:" + map.size());
  48. int taskNum = delayQueue.size();
  49. System.out.println("当前延时任务数量:" + taskNum);
  50. try {
  51. // 从延时队列中获取任务
  52. DelayOrderTask<?> delayOrderTask = delayQueue.take();
  53. if (delayOrderTask != null) {
  54. Runnable task = delayOrderTask.getTask();
  55. if (null == task) {
  56. continue;
  57. }
  58. // 提交到线程池执行task
  59. executor.execute(task);
  60. }
  61. } catch (Exception e) {
  62. e.printStackTrace();
  63. }
  64. }
  65. }
  66. /**
  67. * 添加任务
  68. *
  69. * @param task
  70. * @param time
  71. *            延时时间
  72. * @param unit
  73. *            时间单位
  74. */
  75. public void put(Runnable task, long time, TimeUnit unit) {
  76. // 获取延时时间
  77. long timeout = TimeUnit.NANOSECONDS.convert(time, unit);
  78. // 将任务封装成实现Delayed接口的消息体
  79. DelayOrderTask<?> delayOrder = new DelayOrderTask<>(timeout, task);
  80. // 将消息体放到延时队列中
  81. delayQueue.put(delayOrder);
  82. }
  83. /**
  84. * 删除任务
  85. *
  86. * @param task
  87. * @return
  88. */
  89. public boolean removeTask(DelayOrderTask task) {
  90. return delayQueue.remove(task);
  91. }
  92. }

测试类

  1. package com.delqueue;
  2. import java.util.concurrent.TimeUnit;
  3. import com.test.delayqueue.DelayOrderQueueManager;
  4. import com.test.delayqueue.DelayOrderWorker;
  5. public class Test {
  6. public static void main(String[] args) {
  7. DelayOrderWorker work1 = new DelayOrderWorker();// 任务1
  8. DelayOrderWorker work2 = new DelayOrderWorker();// 任务2
  9. DelayOrderWorker work3 = new DelayOrderWorker();// 任务3
  10. // 延迟队列管理类,将任务转化消息体并将消息体放入延迟对列中等待执行
  11. DelayOrderQueueManager manager = DelayOrderQueueManager.getInstance();
  12. manager.put(work1, 3000, TimeUnit.MILLISECONDS);
  13. manager.put(work2, 6000, TimeUnit.MILLISECONDS);
  14. manager.put(work3, 9000, TimeUnit.MILLISECONDS);
  15. }
  16. }

OK 这就是项目中的具体使用情况,当然具体内容被忽略,整体框架就是这样,还有这里使用java的延时队列但是这种方式是有问题的如果如果down机则会出现任务丢失,所以也可以考虑使用mq、redis来实现

Java 延迟队列使用的更多相关文章

  1. java延迟队列

    大多数用到定时执行的功能都是用任务调度来做的,单身当碰到类似订餐业务/购物等这种业务就不好处理了,比如购物的订单功能,在你的订单管理中有N个订单,当订单超过十分钟未支付的时候自动释放购物车中的商品,订 ...

  2. Spring Boot(十四)RabbitMQ延迟队列

    一.前言 延迟队列的使用场景:1.未按时支付的订单,30分钟过期之后取消订单:2.给活跃度比较低的用户间隔N天之后推送消息,提高活跃度:3.过1分钟给新注册会员的用户,发送注册邮件等. 实现延迟队列的 ...

  3. 使用netty HashedWheelTimer构建简单延迟队列

    背景 最近项目中有个业务,需要对用户新增任务到期后进行业务处理.使用定时任务定时扫描过期时间,浪费资源,且不实时.只能使用延时队列处理. DelayQueue 第一想到的是java自带的延时队列del ...

  4. rabbitmq延迟队列demo

    1. demo详解 1.1 工程结构: 1.2 pom 定义jar包依赖的版本.版本很重要,rabbit依赖spring,两者必须相一致,否则报错: <properties> <sp ...

  5. JUC——延迟队列

    所谓的延迟队列最大的特征是它可以自动通过队列进行脱离,例如:现在有一些对象被临时保存着,但是有可能该集合对象是一个公共对象,那么里面的某些数据如果不在使用的时候就希望其可以在指定的时间达到后自动的消失 ...

  6. Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例

    Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...

  7. RabbitMQ 延迟队列,消息延迟推送

    目录 应用场景 消息延迟推送的实现 测试结果 应用场景 目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如: 淘宝七天自动确认收货.在我们签收商品后,物流系统会在七天后延时发送一个消息给 ...

  8. Redis(二)延迟队列

    1.目录 延迟队列 进一步优化 2.延迟队列 package com.redis; import java.lang.reflect.Type; import java.util.Set; impor ...

  9. Spring Boot (26) RabbitMQ延迟队列

    延迟消息就是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进行消费. 延迟队列 订单业务: 在电商/点餐中,都有下单后30分钟内没有付款,就自动取消订单. 短 ...

随机推荐

  1. 高可用Redis(七):Redis持久化

    1.什么是持久化 持久化就是将数据从掉电易失的内存同步到能够永久存储的设备上的过程 2.Redis为什么需要持久化 redis将数据保存在内存中,一旦Redis服务器被关闭,或者运行Redis服务的主 ...

  2. 第一个 Python 程序

    ## 目标 * 第一个 `HelloPython` 程序* `Python 2.x` 与 `3​​.x` 版本简介* 执行 `Python` 程序的三种方式 * 解释器 —— `python` / ` ...

  3. TopN案例

    准备三份数据 t1 2067 t2 2055 t3 2055 t4 1200 t5 2367 t6 255 t7 2555 t8 12100 t9 20647 t10 245 t11 205 t12 ...

  4. iOS开发之获取当前展示的VC

    /** 递归查找当前显示的VC*/ + (UIViewController *)recursiveFindCurrentShowViewControllerFromViewController:(UI ...

  5. Gradle安装步骤

    一. Gralde介绍 Gradle是基于Groovy语言的项目自动化建构工具,在使用Gradle之前常用的构建工具有Ant和Maven,使用这些工具我们可以用来管理项目依赖,打包,部署和发布等.使用 ...

  6. windows 安装memchched和memcache教程

    Memcached是一个内存缓存系统,而Memcache是php的一个扩展,是php用于操作和管理Memcached的工具.如果安装了Memcached但没有安装Memcache,php无法操控Mem ...

  7. ***报错Class 'Redis' not found in(原创)

    报错:Class 'Redis' not found in 这个报错,表明phpredis 扩展没有安装好,而不是redis没有安装 有没有安装成功这个扩展,可以通过phpinfo来查看. 解决问题的 ...

  8. .net基础学java系列(五)慢性自杀 之 沉沦在IDE中

    最近在慢学习IDEA,总是喜欢与Visual Studio! 其实,对于Visual Studio,它的官方(https://docs.microsoft.com/zh-cn/visualstudio ...

  9. python设计模式---结构型之代理模式

    主要想着nginx:) from abc import ABCMeta, abstractmethod # 结构型设计模式---代理模式 class Actor: def __init__(self) ...

  10. D3---01基础的柱状图制作(转)

    ---文章转自 http://d3.decembercafe.org/index.html  ,Created by 十二月咖啡馆. 一个完整的柱形图包含三部分:矩形.文字.坐标轴. 首先要布置一个大 ...