DelayQueue的使用

本文介绍如何利用Java的DelayQueue实现缓存的延迟过期功能。通过创建生产者和消费者线程,演示了如何添加具有固定过期时间的任务,并在任务过期后由消费者线程取出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景

项目中经常会用到类似一些需要延迟执行的功能,比如缓存。java提供了DelayQueue来很轻松的实现这种功能。Delayed接口中的getDelay方法返回值小于等于0的时候,表示时间到达,可以从DelayQueue中通过take()方法取的到期的对象。到期对象是实现了Delayed的类。


二、代码实战

下面来模拟缓存失效的例子:

启动一个生产者线程,添加4个DelayedItem到DelayQueue队列。启动一个消费者线程从DelayQueue中获取已经到期的DelayedItem。为了看的比较明显一点,这里启动一个计数线程来模拟时钟。每个DelayedItem都有一个固定的失效时间removeTime,当getDelay方法返回值小于等于0的时候,表示有任务到达期限,这里用removeTime-count表示。从运行结果来看,当count值与removeTime值相等时,消费线程将会取得对象,若未到达期限,则消费线程一直阻塞。


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;


public class DelayQueueTest {

    private static DelayQueue delayQueue = new DelayQueue();

    private static long count = 0L;

    private static final int taskNum = 4;

    public static void main(String[] args) throws InterruptedException {

        Object num = new Object();

        final DelayQueueTest delayQueueTest = new DelayQueueTest();
        new Thread(new Runnable() {
            public void run() {
                try {
                    delayQueueTest.producer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        while(true) {
            if(delayQueue.size()==taskNum) {
                break;
            }
        }
        new Thread(new Runnable() {
            public void run() {
                try {
                    delayQueueTest.consumer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();


        new Thread(new Runnable() {
            public void run() {
                try {
                    delayQueueTest.count();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void count() throws InterruptedException {
        while(true) {
            Thread.sleep(1000);
            count++;
            System.out.println("时间值="+count);
            if(taskNum==count) {
                break;
            }
        }
    }

    private void producer() throws InterruptedException {
        for(int i=0; i<taskNum; i++) {
            DelayedItem temp = new DelayedItem(i+"",i,(i+1));
            System.out.println("生产者="+temp);
            delayQueue.put(temp);
        }
    }

    private void consumer() throws InterruptedException {
        while(true) {
            System.out.println("消费者="+delayQueue.take());
            count = 0;
        }
    }


    static class DelayedItem<T> implements  Delayed{
        private String key;
        private T item;
        private long liveTime;
        private long removeTime;

        public DelayedItem(String key,T item,long liveTime) {
            this.key = key;
            this.item = item;
            this.liveTime = liveTime;
            this.removeTime = liveTime;
        }

        /**
         * 当返回值小于等于0时则缓存时间到达,take将取出元素
         * @param unit
         * @return
         */
        public long getDelay(TimeUnit unit) {

            return removeTime-count;
        }

        public int compareTo(Delayed o) {
            if(o instanceof DelayedItem) {
                //已经在队列中存在的对象
                DelayedItem<T> tmpDelayedItem = (DelayedItem<T>)o;
                //System.out.println("比较对象==="+tmpDelayedItem.key+"==="+this.key);
                //失效时间越长的排到队尾
                if(this.removeTime > tmpDelayedItem.removeTime) {
                    return 1;
                } else if(this.removeTime == tmpDelayedItem.removeTime) {
                    return 0;
                } else {
                    return -1;
                }
            }
            return -1;
        }

        @Override
        public String toString() {
            return "DelayedItem{" +
                   "key='" + key + '\'' +
                   ", item=" + item +
                   ", liveTime=" + liveTime +
                   ", removeTime=" + removeTime +
                   '}';
        }
    }
}



运行结果:

生产者=DelayedItem{key='0', item=0, liveTime=1, removeTime=1}
生产者=DelayedItem{key='1', item=1, liveTime=2, removeTime=2}
生产者=DelayedItem{key='2', item=2, liveTime=3, removeTime=3}
生产者=DelayedItem{key='3', item=3, liveTime=4, removeTime=4}
时间值=1
消费者=DelayedItem{key='0', item=0, liveTime=1, removeTime=1}
时间值=1
时间值=2
消费者=DelayedItem{key='1', item=1, liveTime=2, removeTime=2}
时间值=1
时间值=2
时间值=3
消费者=DelayedItem{key='2', item=2, liveTime=3, removeTime=3}
时间值=1
时间值=2
时间值=3
时间值=4
消费者=DelayedItem{key='3', item=3, liveTime=4, removeTime=4}


### 关于 `DelayQueue` 的使用 #### Java 中的 `DelayQueue` `DelayQueue` 是一种特殊的无界阻塞队列,它仅允许插入延迟元素。只有当元素到期时才能从中提取这些元素。此接口通常用于实现诸如缓存清理服务、定时任务调度等功能。 ```java import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; class DelayedTask implements Delayed { private final long triggerTime; private final String taskName; public DelayedTask(String name, int delayInMilliseconds) { this.taskName = name; this.triggerTime = System.currentTimeMillis() + delayInMilliseconds; } @Override public long getDelay(TimeUnit unit) { long diff = triggerTime - System.currentTimeMillis(); return unit.convert(diff, TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { if (this.getDelay(TimeUnit.MILLISECONDS) < ((Delayed)o).getDelay(TimeUnit.MILLISECONDS)) return -1; if (this.getDelay(TimeUnit.MILLISECONDS) > ((Delayed)o).getDelay(TimeUnit.MILLISECONDS)) return 1; return 0; } public void execute(){ System.out.println(taskName+" is executed at "+System.currentTimeMillis()); } } ``` 创建并启动一个线程来不断尝试从 `DelayQueue` 获取已过期的任务: ```java public class TaskScheduler { private static final DelayQueue<DelayedTask> queue = new DelayQueue<>(); public static void main(String[] args){ // 添加一些测试任务 queue.put(new DelayedTask("task-1", 2000)); queue.put(new DelayedTask("task-2", 4000)); Thread schedulerThread = new Thread(() -> { try{ while(true){ DelayedTask task = queue.take(); // 阻塞直到有可用的任务 task.execute(); } }catch(Exception e){ e.printStackTrace(); } }); schedulerThread.start(); } } ``` 上述代码展示了如何定义自定义的 `Delayed` 类型以及如何利用 `DelayQueue` 来管理它们。通过这种方式可以方便地构建基于时间触发的应用场景[^1]。 对于更复杂的业务需求,如分布式环境下的延时消息处理,则可能需要用到像 Redis 这样的外部存储系统配合特定框架完成相似功能[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值