基于JDK-DelayQueue实现的延迟队列

JDK-DelayQueue实现的延迟队列

延迟元素的无限制BlockingQueu,其中元素只能在其延迟到期后才能获取。当元素的getDelay(TimeUnit.NANOSECONDS)方法返回小于或等于零的值时,就会发生过期。即使未到期的元素无法使用take或poll删除,它们也被视为普通元素。此队列不允许出现null 元素。

业务处理类(DelayTask)实现Delayed接口

public class DelayTask implements Delayed {
    private static long currentTime = System.currentTimeMillis();
    // 任务名称
    protected final String taskName;
    // 处理任务时间
    protected final int timeCost;
    // 任务过期时间 (我设置的1分钟+随机数,防止任务冲突在同一时间)
    protected final long scheduleTime;

    // 记录当前任务数量
    protected static final AtomicInteger taskCount = new AtomicInteger(0);

    // 定时任务之间的启动时间间隔在1~2s之间,timeCost表示处理此任务需要的时间,本示例中为2s
    public DelayTask(String taskName, int timeCost) {
        this.taskName = taskName;
        this.timeCost = timeCost;
        taskCount.incrementAndGet();
        currentTime += 60000 + (long) (Math.random() * 1000);
        scheduleTime = currentTime;
    }

    /**
     *  在你put方法时,会调用该方法,该方法是获取,或者设置任务过期时间
     * @param o
     * @return
     */
    @Override
    public int compareTo(Delayed o) {
        return (int) (this.scheduleTime - ((DelayTask) o).scheduleTime);
    }

    /**
     *  在你调用take()方法时调用, 该方法是用任务时间减去当前时间,判断任务是否过期。
     * 在业务可以判定自己返回0还是-1
     * @param unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        long expirationTime = scheduleTime - System.currentTimeMillis();
        return unit.convert(expirationTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 业务处理类
     */
    public void execTask() {
        long startTime = System.currentTimeMillis();
        System.out.println("Task " + taskName + ": schedule_start_time=" + scheduleTime + ",real start time="
                + startTime + ",delay=" + (startTime - scheduleTime));
        try {
            Thread.sleep(timeCost);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

调用线程执行方法

public class DelayTaskComsumer  extends Thread {
    private final BlockingQueue<DelayTask> queue;

    public DelayTaskComsumer(BlockingQueue<DelayTask> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        System.out.println("开始执行任务");
        DelayTask task = null;
        try {
            while (true) {
                System.out.println("正在执行任务");
                // 查询当前在对头任务是否快要过期
                task = queue.take();
                // 调用你执行的业务方法
                task.execTask();
                // 删除对应记录任务
                DelayTask.taskCount.decrementAndGet();
            }
        } catch (InterruptedException e) {
            System.out.println(getName() + " finished");
        }
    }
}

测试类

public class DelayQueueExample {

    public static void main(String[] args) {

        //阻塞队列   父类都是 Queue   实现了 Collection接口
        BlockingQueue<DelayTask> queue = new DelayQueue<DelayTask>();


        // 创建 10个任务进行入队
        for (int i = 0; i < 10; i++) {
            try {
                // 入队, 设置任务处理时间时间两秒
                queue.put(new DelayTask("work " + i, 2000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 创建一个线程组
        ThreadGroup g = new ThreadGroup("Consumers");

        //创建启动线程
        for (int i = 0; i < 1; i++) {
            new Thread(g, new DelayTaskComsumer(queue)).start();
        }


        while (DelayTask.taskCount.get() > 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        g.interrupt();
        System.out.println("Main thread finished");
    }
}

重点 take()方法解析

public E take() throws InterruptedException {
    // 获取锁
    final ReentrantLock lock = this.lock;
    // 可中断锁
    lock.lockInterruptibly();
    try {
        for (;;) {
            E first = q.peek();
            // 如果第一个元素为 null,则阻塞
            if (first == null){
                available.await();
            } else {
                // 获取剩余时间,回调你重写的getDelay()方法 
                long delay = first.getDelay(NANOSECONDS);
                // 等待时间到了,直接执行 poll 返回元素。
                if (delay <= 0){
                    return q.poll();
                }
                first = null; 
                // 当前有其他线程再处理,则进入等待。
                if (leader != null){
                    available.await();
                } else {
                    // 设置 leader 为当前线程
                    Thread thisThread = Thread.currentThread();
                    leader = thisThread;
                    try {
                        // 执行等待
                        available.awaitNanos(delay);
                    } finally {
                        // 释放 leader 信息
                        if (leader == thisThread){
                            leader = null;
                        }
                    }
                }
            }
        }
    } finally {
       // 当前线程出队完成,通知其他出队阻塞的线程继续执行,并释放锁
 
}

总结:
如果用于在取消订单中
1. 服务器重启数据会全部丢失
2. 当订单数量过多会出现OOM异常现象

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值