栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

详解java中DelayQueue的使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

详解java中DelayQueue的使用

简介

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

DelayQueue

先看一下DelayQueue的定义:

public class DelayQueue extends AbstractQueue
  implements BlockingQueue

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

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

为什么这样设计呢?

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

DelayQueue的应用

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

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

@Data
public class DelayedUser implements Delayed {
  private String name;
  private long avaibleTime;

  public DelayedUser(String name, long delayTime){
    this.name=name;
    //avaibleTime = 当前时间+ delayTime
    this.avaibleTime=delayTime + System.currentTimeMillis();

  }

  @Override
  public long getDelay(TimeUnit unit) {
    //判断avaibleTime是否大于当前系统时间,并将结果转换成MILLISEConDS
    long diffTime= avaibleTime- System.currentTimeMillis();
    return unit.convert(diffTime,TimeUnit.MILLISECONDS);
  }

  @Override
  public int compareTo(Delayed o) {
    //compareTo用在DelayedUser的排序
    return (int)(this.avaibleTime - ((DelayedUser) o).getAvaibleTime());
  }
}

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

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

@Slf4j
@Data
@AllArgsConstructor
class DelayedQueueProducer implements Runnable {
  private DelayQueue delayQueue;

  private Integer messageCount;

  private long delayedTime;

  @Override
  public 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
@AllArgsConstructor
public class DelayedQueueConsumer implements Runnable {

  private DelayQueue delayQueue;

  private int messageCount;

  @Override
  public 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中获取对象。

最后看一个调用的例子:

  @Test
  public void useDelayedQueue() throws InterruptedException {
    ExecutorService executor = Executors.newFixedThreadPool(2);

    DelayQueue queue = new DelayQueue<>();
    int messageCount = 2;
    long delayTime = 500;
    DelayedQueueConsumer consumer = new DelayedQueueConsumer(
 queue, messageCount);
    DelayedQueueProducer producer = new DelayedQueueProducer(
 queue, messageCount, delayTime);

    // when
    executor.submit(producer);
    executor.submit(consumer);

    // then
    executor.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

以上就是详解java中DelayQueue的使用的详细内容,更多关于java DelayQueue的资料请关注考高分网其它相关文章!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/130965.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号