java利用delayedQueue实现本地的延迟队列

网友投稿 253 2023-05-21


java利用delayedQueue实现本地的延迟队列

一、了解DelayQueue

DelayQueue是什么?

DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。

注意:不能将null元素放置到这种队列中。

DelayQueue能做什么?

在我们的业务中通常会有一些需求是这样的:

淘宝订单业务:下单之后如果三十分钟之内没有付款就自动取消订单。

饿了吗订餐通知:下单成功后60s之后给用户发送短信通知。

那么这类业务我们可以总结出一个特点:需要延迟工作。

由此的情况,就是我们的DelayQueue应用需求的产生。

二、怎么用DelayQueue来解决这类的问题

先声明一个Delayed的对象

import java.util.concurrent.Delayed;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicLong;

/**

*

* [任务调度系统]

*

* [队列中要执行的任务]

*

*

* @author wangguangdong

* @version 1.0

* @Date 2015年11月22日19:46:39

*/

public class Task implements Delayed {

/**

* 到期时间

*/

private final long time;

/**

* 问题对象

*/

private final T task;

private static final AtomicLong atomic = new AtomicLong(0);

private final long n;

public Task(long timeout, T t) {

this.time = System.nanoTime() + timeout;

this.task = t;

this.n = atomic.getAndIncrement();

}

/**

* 返回与此对象相关的剩余延迟时间,以给定的时间单位表示

*/

@Override

public long getDelay(TimeUnit unit) {

return unit.convert(this.time - System.nanoTime(), TimeUnit.NANOSECONDS);

}

@Override

public int compareTo(Delayed other) {

// TODO Auto-generated method stub

if (other == this) // compare zero ONLY if same object

return 0;

if (other instanceof Task) {

Task x = (Task) other;

long diff = time - x.time;

if (diff < 0)

return -1;

else if (diff > 0)

return 1;

else if (n < x.n)

return -1;

else

return 1;

}

long d = (getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS));

return (d == 0) ? 0 : ((d < 0) ? -1 : 1);

}

public T getTask() {

return this.task;

}

@Override

public int hashCode() {

return task.hashCode();

}

@Override

public boolean equals(Object object) {

if (object instanceof Task) {

return object.hashCode() == hashCode() ? true : false;

}

return false;

}

}

再实现一个管理延迟任务的类

import org.apache.log4j.Logger;

import java.util.concurrent.DelayQueue;

import java.util.concurrent.Executor;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

/**

*

* [任务调度系统]

*

* [后台守护线程不断的执行检测工作]

*

*

* @author wangguangdong

* @version 1.0

* @Date 2015年11月23日14:19:40

*/

public class TaskQueueDaemonThread {

private static final Logger LOG = Logger.getLogger(TaskQueueDaemonThread.class);

private TaskQueueDaemonThread() {

}

private static class LazyHolder {

private static TaskQueueDaemonThread taskQueueDaemonThread = new TaskQueueDaemonThread();

}

public static TaskQueueDaemonThread getInstance() {

return LazyHolder.taskQueueDaemonThread;

}

Executor executor = Executors.newFixedThreadPool(20);

/**

* 守护线程

*/

private Thread daemonThread;

/**

* 初始化守护线程

*/

public void init() {

daemonThread = new Thread(() -> execute());

daemonThread.setDaemon(true);

daemonThread.setName("Task Queue Daemon Thread");

daemonThread.start();

}

private void execute() {

System.out.println("start:" + System.currentTimeMillis());

while (true) {

try {

//从延迟队列中取值,如果没有对象过期则队列一直等待,

Task t1 = t.take();

if (t1 != null) {

//修改问题的状态

Runnable task = t1.getTask();

if (task == null) {

continue;

}

executor.execute(task);

LOG.info("[at task:" http://+ task + "] [Time:" + System.currentTimeMillis() + "]");

}

} catch (Exception e) {

e.printStackTrace();

break;

}

}

}

/**

* 创建一个最初为空的新 DelayQueue

*/

private DelayQueue t = new DelayQueue<>();

/**

* 添加任务,

* time 延迟时间

* task 任务

* 用户为问题设置延迟时间

*/

public void put(long time, Runnable task) {

//转换成ns

long nanoTime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS);

//创建一个任务

Task k = new Task(nanoTime, task);

//将任务放在延迟的队列中

t.put(k);

}

/**

* 结束订单

* @param task

*/

public boolean endTask(Task task){

return t.remove(task);

}

}

使用方法

在容器初始化的时候调用init方法.

实现一个runnable接口的类,调用TaskQueueDaemonThread的put方法传入进去.

如果需要实现动态的取消任务的话,需要task任务的类重新hashcode方法,最好用业务限制hashcode的冲突发生.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Mybatis 一对多和多对一关联查询问题
下一篇:Spring AOP 自定义注解的实现代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~