文章目录

  • 简介
  • DelayQueue
  • DelayQueue的应用
  • 总结


java中DelayQueue的使用


简介

今天给大家介绍一下DelayQueue,DelayQueue是BlockingQueue的一种,所以它是线程安全的,DelayQueue的特点就是插入Queue中的数据可以按照自定义的delay时间进行排序。只有delay时间小于0的元素才能够被取出。

DelayQueue

先看一下DelayQueue的定义:

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>implements BlockingQueue<E>

从定义可以看到,DelayQueue中存入的对象都必须是Delayed的子类。

Delayed继承自Comparable,并且需要实现一个getDelay的方法。

为什么这样设计呢?

因为DelayQueue的底层存储是一个PriorityQueue,在之前的文章中我们讲过了,PriorityQueue是一个可排序的Queue,其中的元素必须实现Comparable方法。而getDelay方法则用来判断排序后的元素是否可以从Queue中取出。

DelayQueue的应用

DelayQueue一般用于生产者消费者模式,我们下面举一个具体的例子。

首先要使用DelayQueue,必须自定义一个Delayed对象:

@Datapublic class DelayedUser implements Delayed {private String name;private long avaibleTime;public DelayedUser(String name, long delayTime){this.name=name;//avaibleTime = 当前时间+ delayTimethis.avaibleTime=delayTime + System.currentTimeMillis();}@Overridepublic long getDelay(TimeUnit unit) {//判断avaibleTime是否大于当前系统时间,并将结果转换成MILLISECONDSlong diffTime= avaibleTime- System.currentTimeMillis();return unit.convert(diffTime,TimeUnit.MILLISECONDS);}@Overridepublic int compareTo(Delayed o) {//compareTo用在DelayedUser的排序return (int)(this.avaibleTime - ((DelayedUser) o).getAvaibleTime());}}

上面的对象中,我们需要实现getDelay和compareTo方法。

接下来我们创建一个生产者:

@Slf4j@Data@AllArgsConstructorclass DelayedQueueProducer implements Runnable {private DelayQueue<DelayedUser> delayQueue;private Integer messageCount;private long delayedTime;@Overridepublic void run() {for (int i = 0; i < messageCount; i++) {try {DelayedUser delayedUser = new DelayedUser(new Random().nextInt(1000)+"", delayedTime);log.info("put delayedUser {}",delayedUser);delayQueue.put(delayedUser);Thread.sleep(500);} catch (InterruptedException e) {log.error(e.getMessage(),e);}}}}

在生产者中,我们每隔0.5秒创建一个新的DelayedUser对象,并入Queue。

再创建一个消费者:

@Slf4j@Data@AllArgsConstructorpublic class DelayedQueueConsumer implements Runnable {private DelayQueue<DelayedUser> delayQueue;private int messageCount;@Overridepublic void run() {for (int i = 0; i < messageCount; i++) {try {DelayedUser element = delayQueue.take();log.info("take {}",element );} catch (InterruptedException e) {log.error(e.getMessage(),e);}}}}

在消费者中,我们循环从queue中获取对象。

最后看一个调用的例子:

    @Testpublic void useDelayedQueue() throws InterruptedException {ExecutorService executor = Executors.newFixedThreadPool(2);DelayQueue<DelayedUser> queue = new DelayQueue<>();int messageCount = 2;long delayTime = 500;DelayedQueueConsumer consumer = new DelayedQueueConsumer(queue, messageCount);DelayedQueueProducer producer = new DelayedQueueProducer(queue, messageCount, delayTime);// whenexecutor.submit(producer);executor.submit(consumer);// thenexecutor.awaitTermination(5, TimeUnit.SECONDS);executor.shutdown();}

上面的测试例子中,我们定义了两个线程的线程池,生产者产生两条消息,delayTime设置为0.5秒,也就是说0.5秒之后,插入的对象能够被获取到。

线程池在5秒之后会被关闭。

运行看下结果:

[pool-1-thread-1] INFO com.flydean.DelayedQueueProducer - put delayedUser DelayedUser(name=917, avaibleTime=1587623188389)[pool-1-thread-2] INFO com.flydean.DelayedQueueConsumer - take DelayedUser(name=917, avaibleTime=1587623188389)[pool-1-thread-1] INFO com.flydean.DelayedQueueProducer - put delayedUser DelayedUser(name=487, avaibleTime=1587623188899)[pool-1-thread-2] INFO com.flydean.DelayedQueueConsumer - take DelayedUser(name=487, avaibleTime=1587623188899)

我们看到消息的put和take是交替进行的,符合我们的预期。

如果我们做下修改,将delayTime修改为50000,那么在线程池关闭之前插入的元素是不会过期的,也就是说消费者是无法获取到结果的。

总结

DelayQueue是一种有奇怪特性的BlockingQueue,可以在需要的时候使用。

本文的例子https://github.com/ddean2009/learn-java-collections

©著作权归作者所有:来自51CTO博客作者ddean2009的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. java中wait和sleep的区别
  2. java并发中的Synchronized关键词
  3. java.util.concurrent简介
  4. java中ThreadLocal的使用
  5. java并发中CountDownLatch的使用
  6. java中Locks的使用
  7. 在java中构建高效的结果缓存
  8. java中ThreadPool的介绍和使用
  9. 挑战10个最难回答的Java面试题

随机推荐

  1. 数据存储和界面展示一
  2. Android 4.4 SD卡文件读写变化
  3. Android菜鸟笔记3-Activity切换
  4. 【Mark 】AndroidStudio_移动应用开发
  5. 转-Android UI学习 - Tab的学习和使用
  6. Android UI LinearLayout权限级别与Table
  7. android滚动条
  8. android调用系统功能
  9. View的xml的属性作用大剖析
  10. TextView和EidtText使用技巧