大多数用到定时执行的功能都是用任务调度来做的,单身当碰到类似订餐业务/购物等这种业务就不好处理了,比如购物的订单功能,在你的订单管理中有N个订单,当订单超过十分钟未支付的时候自动释放购物车中的商品,订单失效。这种高频率的延迟任务再用任务调度(定时)实现就得不偿失了。推荐用Java延迟队列来实现,DelayQueue是java.util.concurrent中提供的一个类DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中中取走。这种队列是有序的,即对头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。

1、java延迟队列实现方式

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong; //任务线程 实现delayed接口
public class DelayItem<T extends Runnable> implements Delayed {
//到期时间
private final long time;
//任务对象
private final T task;
//原子类
private static final AtomicLong atomic = new AtomicLong(0);
private final long n; public DelayItem(long timeout, T t) {
this.time = System.nanoTime() + timeout;
this.task = t;
this.n = atomic.getAndIncrement();
}
//返回与此对象相关的剩余延迟时间,以给定的时间单位表示
public long getDelay(TimeUnit unit) {
return unit.convert(this.time - System.nanoTime(),TimeUnit.NANOSECONDS);
} public int compareTo(Delayed other) {
if(other == this) {
return 0;
}
if(other instanceof DelayItem) {
DelayItem<?> x = (DelayItem<?>)other;
long diff = tiem - 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 DelayItem){
return object.hashCode() == hashCode() ? true : false;
}
return false;
}
} //管理延迟任务的类
import java.util.Map;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
//延迟队列存放有效期对象
public class ItemQueueThread {
private static final Logger logger = Logger.getLogger(this.class);
private ItemQueueThread(){}
//延迟加载(线程安全)
private static class LazyHolder{
private static ItemQueueThread itemQueueThread = new ItemQueueThread();
}
public static ItemQueueThread getInstance(){
return LazyHolder.itemQueueThread;
}
//缓存线程池
ExecutorService executor = Executors.newCacheThreadPool();
//线程
private Thread daemonThead;
//初始化线程
public void init() {
daemonThread = new Thread(() -> {
try{
execute();
}cathc(InterruptedException e){
e.printStackTrace();
logger.info(e.getMessage());
}
});
System.out.println("init......start");
daemonThread.start();
} private void execute() throws InterrupedException {
while(true) {
Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
System.out.println("线程数...." + map.size());
System.out.println(System.currentTimeMills());
System.out.println(item.size());
System.out.println("线程状态----" + Thread.currentThread().getState());
try{
//从延迟队列中取值,如果没有对象过期责队列一直等待
DelayItem<?> t1 = item.take();
if(t1 != null){
Runnable task = t1.getTask();
if(task == null){
continue;
}
executor.execute(task);
}
}catch(Exception e) {
e.printStackTrace();
logger.info(e.getMessage());
}
}
}
//创建空的延迟队列
private DelayQueue<DelayItem<?>> item = new DelayQueue<>();
//往队列中添加任务
public void put(long time, Runnable task, TimeUnit timeUnit){
//转换成ns
long nanoTime = TimeUnit.NANOSECONDS.convert(time,timeUnit);
DelayItem<?> k = new DelayItem(nanoTime,task);
item.put(k);_:
}
//结束任务
public boolean endTask(DelayItem<Runnable> task){
return item.remove(task);
}
} //把需要延迟的功能代码单独抽取出来作为一个类,继承Runnable实现run方法
public class DataDemo implements Runnable {
int a = -1;
public DataDemo(int i){
this.a = i;
}
@Override
public void run(){
System.out.println("超时,要撤销订单...." + a);
}
} //test class
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class DelayTest{
public static void main(String[] args){
ItemQueueThread ith = ItemQueueThread.getInstance();
ith.init();
Random r = new Random();
for(int i = 0; i < 5; i++){
int a = r.nextInt(20);
System.out.println("预先知道等待时间:" + a);
DataDemo dd = new DataDemo(a);//创建一个任务对象
ith.put(a,dd,TimeUnit.SECONDS);//将任务添加到队列中
}
}
}
//注意ItemQueueThread的init方法,要在容器初始化的时候就要执行,或在第一次put延迟对象任务之前就要初始化完成,当设定的延迟时间到期时会执行任务对象中的run
}

  

2、定时任务实现方式

引入quartz包

import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory; public class DeplayQuartzImpl implements Job{ @Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//doing somethings
System.out.println("going scan database...");
} public static void main(String[] args) throws SchedulerException { //create task
JobDetail jobDetail = JobBuilder.newJob(DeplayQuartzImpl.class).withIdentity("job_1", "group_1").build(); //create trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger_1", "group_trigger")
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3).repeatForever())
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler(); //put task into trigger
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} }

实现java的Delayed接口简介版

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit; public class JdkDelayImpl implements Delayed{ private String orderId;
private long timeout; public JdkDelayImpl(String orderId, long timeout) {
this.orderId = orderId;
this.timeout = timeout + System.nanoTime();
} @Override
public int compareTo(Delayed delayed) {
if(delayed == this)
return 0;
JdkDelayImpl t = (JdkDelayImpl) delayed;
long d = (getDelay(TimeUnit.NANOSECONDS) - t.getDelay(TimeUnit.NANOSECONDS));
return (d == 0) ? 0 : ((d < 0) ? -1 : 1);
} @Override
public long getDelay(TimeUnit unit) {
return unit.convert(timeout - System.nanoTime(), TimeUnit.NANOSECONDS );
} void print() {
System.out.println(orderId + " order will being delete...");
} public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("001");
list.add("002");
list.add("003");
list.add("004");
list.add("005"); DelayQueue<JdkDelayImpl> queue = new DelayQueue<JdkDelayImpl>();
long start = System.currentTimeMillis();
for(int i = 0; i < 5; i++) {
queue.put(new JdkDelayImpl(list.get(i),
TimeUnit.NANOSECONDS.convert(3, TimeUnit.SECONDS)));
try {
queue.take().print();
System.out.println("after: " + (System.currentTimeMillis() - start)
+ " milliSeconds"); } catch (Exception e) {
}
}
} }

3、基于netty方式,添加netty包

import java.util.concurrent.TimeUnit;

import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask; public class NettyDeplayImpl { static class MyTimeTask implements TimerTask { boolean flag; public MyTimeTask(boolean flag) {
this.flag = flag;
} @Override
public void run(Timeout arg0) throws Exception {
System.out.println("going to delete order...");
this.flag = false;
}
} public static void main(String[] args) {
MyTimeTask timeTask = new MyTimeTask(true);
Timer timer = new HashedWheelTimer();
timer.newTimeout(timeTask, 5, TimeUnit.SECONDS);
int i = 1;
while(timeTask.flag) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.err.println(i + " seconds gone");
i++;
}
}
}

java延迟队列的更多相关文章

  1. Java 延迟队列使用

    延时队列,第一他是个队列,所以具有对列功能第二就是延时,这就是延时对列,功能也就是将任务放在该延时对列中,只有到了延时时刻才能从该延时对列中获取任务否则获取不到…… 应用场景比较多,比如延时1分钟发短 ...

  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. ElasticSearch(java) 创建索引

    搜索]ElasticSearch Java Api(一) -创建索引 标签: elasticsearchapijavaes 2016-06-19 23:25 33925人阅读 评论(30) 收藏 举报 ...

  2. 【学习笔记】圆方树(CF487E Tourists)

    终于学了圆方树啦~\(≧▽≦)/~ 感谢y_immortal学长的博客和帮助 把他的博客挂在这里~ 点我传送到巨佬的博客QwQ! 首先我们来介绍一下圆方树能干什么呢qwq 1.将图上问题简化到树上问题 ...

  3. 3.自定义返回json格式的数据给前台(自定义Controller类中的Json方法)

    在mvc的项目中,我们前台做一些操作时,后台要返回一些结果给前台,这个时候我们就需要有一个状态来标识到底是什么类型的错误, 例如: 执行删除的时候,如果操作成功(1行受影响),我们需要返回状态为1并输 ...

  4. Vue学习笔记-插槽基本使用

    为了让我们的组件更加具有扩展性,可以使用插槽 <div id="app"> <cpn> <span>返回</span> <in ...

  5. 重新调整动态vhdx占用的空间

    优化vhd:https://docs.microsoft.com/en-us/powershell/module/hyper-v/optimize-vhd?view=win10-ps 1. 弹出vhd ...

  6. Linux Bash Shell快速入门 (三)

    forfor 循环结构与 C 语言中有所不同,在 BASH 中 for 循环的基本结构是: for $var in dostatmentsdone 其中 $var 是循环控制变量, 是 $var 需要 ...

  7. RHEL 使用epel源

    转自http://www.linuxidc.com/Linux/2012-10/71850.htm 设置epel源.方法如下: 32位系统选择:rpm -ivh http://download.Fed ...

  8. Zlib not installed

    若提示:zlib not installed   wget http://zlib.net/zlib-1.2.8.tar.gz   tar zxf zlib-1.2.8.tar.gz cd zlib- ...

  9. pip安装第三方库报错Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None))...

    pip安装第三方库时报错Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None))...,详细报错见下 ...

  10. 洛谷 P1522 牛的旅行 Cow Tours——暴力枚举+最短路

    先上一波题目  https://www.luogu.org/problem/P1522 这道题其实就是给你几个相互独立的连通图 问找一条新的路把其中的两个连通图连接起来后使得新的图中距离最远的两个点之 ...