使用DelayQueue延迟任务
业务场景:
- 定单到期自动失效,并向用发送短信或者微信消息模板
- 缓存失效
解决这类业务也有其他方案:
- spring + quartz: 每隔几秒钟就去扫描数据库中失效的记录
- spring + redis (keyspace notification)
缺点:
- 在单机上是一种不错的选择,但在分布式环境下需要自己实现同步,不如quartz
- 数据放在内存,需要实现数据持久化,不如quartz
优点:
- 相比较quartz,就不用每隔几秒钟就去扫描数据库中失效的记录
要使用DelayQueue,要求放入DelayQueue
中的实体类实现Delayed
接口
public interface Delayed extends Comparable<Delayed> {
/**
* Returns the remaining delay associated with this object, in the
* given time unit.
*
* @param unit the time unit
* @return the remaining delay; zero or negative values indicate
* that the delay has already elapsed
*/
long getDelay(TimeUnit unit);
}
DelayTask.java
:
public class DelayTask implements Delayed {
private long expiredTime;
private String name;
public DelayTask(long expiredTime, String name) {
this.expiredTime = expiredTime;
this.name = name;
}
@Override
public long getDelay(TimeUnit unit) { //还有多久过期
//expiredTime时间单位要和当前时间单位统一!!
return this.expiredTime - System.currentTimeMillis();
}
@Override
public int compareTo(Delayed o) {
int dif = (int) (this.getDelay(TimeUnit.NANOSECONDS) -o.getDelay(TimeUnit.NANOSECONDS));
return dif > 0 ? 1: dif < 0 ? -1:0;
}
@Override
public String toString() {
return "DelayTask{" +
"expiredTime=" + expiredTime +
", name='" + name + '\'' +
'}';
}
}
测试用例:
public static void main(String[] args) throws InterruptedException {
DelayQueue<DelayTask> queue = new DelayQueue<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
System.out.println("start: "+ sdf.format(new Date()));
long start = System.currentTimeMillis();
TimeUnit timeUnit = TimeUnit.MILLISECONDS;
queue.add(new DelayTask(timeUnit.convert(10, TimeUnit.SECONDS)+start, "task-1"));
queue.add(new DelayTask(timeUnit.convert(4, TimeUnit.SECONDS)+ start, "task-2"));
queue.add(new DelayTask(timeUnit.convert(7, TimeUnit.SECONDS)+start, "task-3"));
while (!queue.isEmpty()){
DelayTask task = queue.take();
if (task != null){
System.out.println("get task: "+ task+ " at "+ sdf.format(new Date()));
}
}
System.out.println("end...");
}
结果:
start: 2018-04-06 10:50:45:538
get task: DelayTask{expiredTime=1522983049543, name='task-2'} at 2018-04-06 10:50:49:543 -->与开始时间相差4秒
get task: DelayTask{expiredTime=1522983052543, name='task-3'} at 2018-04-06 10:50:52:543 -->与开始时间相差7秒
get task: DelayTask{expiredTime=1522983055543, name='task-1'} at 2018-04-06 10:50:55:543 -->与开始时间相差10秒
end...
顺便了解一下TimeUnit
:
TimeUnit timeUnit = TimeUnit.HOURS;
System.out.println(timeUnit.convert(2, TimeUnit.DAYS)); 将2天转成以小时为单位
//结果
48