初学者java入门基础知识 java双端队列原理( 四 )



6.关于 ArrayBlockingQueue 说法不正确的是?A:ArrayBlockingQueue 是线程安全的 B:ArrayBlockingQueue 元素允许为 null C:ArrayBlockingQueue 主要应用场景是“生产者-消费者”模型 D:ArrayBlockingQueue 必须显示地设置容量 答:B 题目解析:ArrayBlockingQueue 不允许元素为 null , 如果添加一个 null 元素 , 会抛 NullPointerException 异常 。
7.以下程序执行的结果是什么?PriorityQueue priorityQueue = new PriorityQueue();priorityQueue.add(null);System.out.println(priorityQueue.size());答:程序执行报错 , PriorityQueue 不能插入 null 。
8.Java 中常见的阻塞队列有哪些?答:Java 中常见的阻塞队列如下:

  • ArrayBlockingQueue , 由数组结构组成的有界阻塞队列;
  • PriorityBlockingQueue , 支持优先级排序的无界阻塞队列;
  • SynchronousQueue , 是一个不存储元素的阻塞队列 , 会直接将任务交给消费者 , 必须等队列中的添加元素被消费后才能继续添加新的元素;
  • LinkedBlockingQueue , 由链表结构组成的阻塞队列;
  • DelayQueue , 支持延时获取元素的无界阻塞队列 。
9.有界队列和无界队列有哪些区别?答:有界队列和无界队列的区别如下:
  • 有界队列:有固定大小的队列叫做有界队列 , 比如:new ArrayBlockingQueue(6) , 6 就是队列的大小 。
  • 无界队列:指的是没有设置固定大小的队列 , 这些队列的特点是可以直接入列 , 直到溢出 。它们并不是真的无界 , 它们最大值通常为 Integer.MAXVALUE , 只是平常很少能用到这么大的容量(超过 Integer.MAXVALUE) , 因此从使用者的体验上 , 就相当于 “无界” 。
10.如何手动实现一个延迟消息队列?答:说到延迟消息队列 , 我们应该可以第一时间想到要使用 DelayQueue 延迟队列来解决这个问题 。实现思路 , 消息队列分为生产者和消费者 , 生产者用于增加消息 , 消费者用于获取并消费消息 , 我们只需要生产者把消息放入到 DelayQueue 队列并设置延迟时间 , 消费者循环使用 take() 阻塞获取消息即可 。完整的实现代码如下:
public class CustomDelayQueue {// 消息编号static AtomicInteger MESSAGENO = new AtomicInteger(1);public static void main(String[] args) throws InterruptedException {DelayQueue<DelayedElement> delayQueue = new DelayQueue<>();// 生产者1producer(delayQueue, "生产者1");// 生产者2producer(delayQueue, "生产者2");// 消费者consumer(delayQueue);}//生产者private static void producer(DelayQueue<DelayedElement> delayQueue, String name) {new Thread(new Runnable() {@Overridepublic void run() {while (true) {// 产生 1~5 秒的随机数long time = 1000L * (new Random().nextInt(5) + 1);try {Thread.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}// 组合消息体String message = String.format("%s , 消息编号:%s 发送时间:%s 延迟:%s 秒",name, MESSAGENO.getAndIncrement(), DateFormat.getDateTimeInstance().format(new Date()), time / 1000);// 生产消息delayQueue.put(new DelayedElement(message, time));}}}).start();}//消费者private static void consumer(DelayQueue<DelayedElement> delayQueue) {new Thread(new Runnable() {@Overridepublic void run() {while (true) {DelayedElement element = null;try {// 消费消息element = delayQueue.take();System.out.println(element);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();} // 延迟队列对象static class DelayedElement implements Delayed {// 过期时间(单位:毫秒)long time = System.currentTimeMillis();// 消息体String message;// 参数:delayTime 延迟时间(单位毫秒)public DelayedElement(String message, long delayTime) {this.time += delayTime;this.message = message;}@Override// 获取过期时间public long getDelay(TimeUnit unit) {return unit.convert(time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);}@Override// 队列元素排序public int compareTo(Delayed o) {if (this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS))return 1;else if (this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS))return -1;elsereturn 0;}@Overridepublic String toString() {// 打印消息return message + " |执行时间:" + DateFormat.getDateTimeInstance().format(new Date());}}}

推荐阅读