DelayQueue延迟队列

DelayQueue是一个支持延时获取元素的无界阻塞队列。队列中的元素必须实现Delayed接口,在创建元素的时候可以指定多久才能从队列中获取当前元素,只有在延迟期满时才能从队列中获取元素。

我们可以将DelayQueue运用在以下应用场景:

缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。

定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,从比如TimerQueue就是使用DelayQueue实现的。

——以上摘自Java并发编程的艺术

下面是自已撸的一个小栗子

1、用于执行通知任务的队列元素

packagecom.dreyer.concurrent;

importjava.util.concurrent.Delayed;

importjava.util.concurrent.TimeUnit;

/**

*@description通知延迟队列

*@author:Dreyer

*@date:16/4/27 下午2:40

*/

public classNotifyTaskimplementsRunnable,Delayed {

// 通知名称

privateStringnotifyTaskName;

// 执行时间

private longexecuteTime;

publicNotifyTask(String notifyTaskName, longexecuteTime) {

this.notifyTaskName= notifyTaskName;

this.executeTime= executeTime;

}

/**

* 设置延迟时间

*@paramunit

*@return

*/

public longgetDelay(TimeUnit unit) {

returnunit.convert(executeTime- System.currentTimeMillis(),unit.MILLISECONDS);

}

/**

* 用来指定元素的顺序,让延时时间最长的放在队列的末尾

*@paramo

*@return

*/

public intcompareTo(Delayed o) {

NotifyTask notifyTask = (NotifyTask) o;

returnexecuteTime> notifyTask.executeTime?1: (executeTime< notifyTask.executeTime? -1:0);

}

public voidrun() {

System.out.println("当前时间毫秒数:"+ System.currentTimeMillis() +","+this.toString() +"正在执行...");

}

@Override

publicStringtoString() {

return"NotifyTask{"+

"notifyTaskName='"+notifyTaskName+'\''+

", executeTime="+executeTime+

'}';

}

}

2、测试类

packagecom.dreyer.concurrent;

importjava.util.Random;

importjava.util.concurrent.DelayQueue;

/**

*@description测试类

*@author:Dreyer

*@date:16/4/27 下午3:56

*/

public classNotifyTaskTest {

/**

* 通知任务存放的延时队列

*/

public staticDelayQueuetasks=newDelayQueue();

public static voidmain(String[] args) {

Random random =newRandom();

for(inti =0;i <5;i++) {

// 随机产生一个秒数

intseconds = random.nextInt(5) +1;

NotifyTask notifyTask =newNotifyTask("任务"+ i,System.currentTimeMillis() + (seconds *1000));

tasks.put(notifyTask);

}

longstart = System.currentTimeMillis();

while(true) {

NotifyTask notifyTask =tasks.poll();

if(notifyTask !=null) {

notifyTask.run();

}

// 如果队列中的元素全部被取完,则跳出循环

if(tasks.size() ==0) {

break;

}

System.out.println("is running......");

}

System.out.println("耗时:"+ (System.currentTimeMillis() - start) /1000+"ms");

}

}

3、执行结果(部分)

......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

当前时间毫秒数:1461762721192,NotifyTask{notifyTaskName='任务0', executeTime=1461762721192}正在执行...

is running......

当前时间毫秒数:1461762721192,NotifyTask{notifyTaskName='任务1', executeTime=1461762721192}正在执行...

耗时:5ms

从结果中,我们可以看出NotifyTask的executeTime是设置在什么时候执行,那它的执行时间也会是那个时候

注意点:

栗子中的构造函数设置的延迟时间参数executeTime的单位是毫秒,getDelay()方法可以指定任意单位(栗子中指定的是毫秒),建议不要使用值过大的单位,比如秒 / 分,如果getDelay()方法返回的是一个负数,那队列中能立即获取到元素。

关于DelayQueue在公司项目里面的应用场景主要是:

订单支付成功或者失败后要给商户发送相应的通知,针对同一条通知记录,如果是第一次发,则需要等待的时间是0分钟,第二次发则需要等待1分钟,第三次发则需要等待3分钟,即发送次数每+1,则需要等待的时长也要相应的增加,那使用DelayQueue就能很好的实现这个功能了。

你可能感兴趣的:(DelayQueue延迟队列)