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