Queue 相关知识

1. Queue 与 Deque 的区别

Queue 是单端队列,只能从一端插入元素,另一端删除元素,实现上一般遵循先进先出(FIFO)规则。Deque 是双端队列,在队列的两端均可以插入或删除元素。

2. ArrayDeque 和 LinkedList

2.1 ArrayDeque

ArrayDeque 是基于动态循环数组和双指针来实现

ArrayDeque 插入时可能存在扩容过程, 不过均摊后的插入操作依然为 O(1)。

ArrayDeque 不支持存储 NULL 数据

2.2 LinkedList

LinkedList 则通过双向链表来实现。

LinkedList 插入不需要扩容,但是每次插入数据时均需要申请新的堆空间,均摊性能相比较差。

LinkedList 支持存放null值。

3. PriorityQueue

1.PriorityQueue是优先级队列,每次出队总是出队优先级最高的元素。

2.PriorityQueue 基于二叉堆实现,默认是小顶堆,可以传入一个 Comparator 进行定制排序。

3.PriorityQueue 底层是可变长数组,数组的结构实际上是一个完全二叉树的线性表示。通过堆元素的上浮和下沉,实现了在 O(logn) 的时间复杂度内插入元素和删除堆顶元素。

4.PriorityQueue 是非线程安全的,且不支持存储 NULL 和 non-comparable 的对象。

4. ArrayBlockingQueue

4.1 ArrayBlockingQueue 是什么?它的特点是什么?

  1. ArrayBlockingQueue是阻塞队列。支持当队列没有元素时一直阻塞,直到有元素再获取;还支持如果队列已满,一直等到队列可以放入新元素时再放入。BlockingQueue 常用于生产者-消费者模型中,生产者线程会向队列中添加数据,而消费者线程会从队列中取出数据进行处理。
  2. 底层采用数组实现,ArrayBlockingQueue 是有界队列,必须在创建时指定容量大小,一旦创建,大小不可变。
  3. ArrayBlockingQueue 常用于多线程之间的数据共享,其并发控制采用可重入锁 ReentrantLock 。支持公平和非公平两种锁,默认是非公平锁。公平锁基于先来先服务,非公平锁基于竞争
  4. 通过 Condition 实现线程间的等待和唤醒操作。

4.2 ArrayBlockingQueue 和 LinkedBlockingQueue 有什么异同?

  • 相同

    • 都是BlockingQueue 的实现类,它们都是线程安全的。
  • 不同

    • 底层实现:ArrayBlockingQueue 基于数组实现,而 LinkedBlockingQueue 基于链表实现。
    • 是否有界:ArrayBlockingQueue 是有界队列,必须在创建时指定容量大小。LinkedBlockingQueue 创建时可以不指定容量大小,默认是Integer.MAX_VALUE,也就是无界的。但也可以指定队列大小,从而成为有界的。
    • 锁是否分离: ArrayBlockingQueue中的锁是没有分离的,即生产和消费用的是同一个锁;LinkedBlockingQueue中的锁是分离的,即生产用的是putLock,消费是takeLock,这样可以减少线程竞争。

4.3 ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别?

  1. 底层实现:ArrayBlockingQueue 基于数组实现,而 ConcurrentLinkedQueue 基于链表实现。
  2. 是否有界:ArrayBlockingQueue 是有界队列,必须在创建时指定容量大小,而 ConcurrentLinkedQueue 是无界队列,可以动态地增加容量。
  3. 是否阻塞:ArrayBlockingQueue 支持阻塞和非阻塞存取, ConcurrentLinkedQueue 仅支持非阻塞式存取。

5. DelayQueue

5.1 DelayQueue 的实现原理是什么?

  1. DelayQueue是延迟队列,确保元素只有在其延迟时间到期后才能被取出。
  2. 底层是优先队列 PriorityQueue,PriorityQueue 基于二叉堆实现,默认是小顶堆,可以传入一个 Comparator定制排序。
  3. DelayQueue并发控制采用可重入锁 ReentrantLock 。支持公平和非公平两种锁,默认是非公平锁。公平锁基于先来先服务,非公平锁基于竞争
  4. 通过 Condition 实现线程间的等待和唤醒操作。

5.2 DelayQueue 的实现是否线程安全?

  1. DelayQueue并发控制采用可重入锁 ReentrantLock 。支持公平和非公平两种锁,默认是非公平锁。公平锁基于先来先服务,非公平锁基于竞争
  2. 通过 Condition 实现线程间的等待和唤醒操作。

5.3 DelayQueue 的使用场景有哪些?

  1. 定时任务调度

    1. 将需要执行的任务封装成对象,DelayQueue会自动按照剩余时间进行排序,保证任务能够按照时间顺序先后执行。
  2. 缓存过期删除

    1. 数据被缓存到内存之后,我们可以将缓存的 key 封装成一个对象放入延迟队列,当缓存过期时,拿到 key将内存中数据删除。

5.4 DelayQueue 中 Delayed 接口的作用是什么?

若希望元素能够存放到 DelayQueue 中,就必须重写Delayed 接口的 getDelay() 方法和 compareTo() 方法,getDelay() 获取元素剩余时间,当时间相同时,用compareTo方法对元素进行比较。

5.5 DelayQueue 和 Timer/TimerTask 的区别是什么?

DelayQueue 和 Timer/TimerTask 都可以用于实现定时任务调度,但是它们的实现方式不同。DelayQueue 是基于优先级队列,需要与 ExecutorService 等并发工具结合使用来处理从队列中取出的任务;而 Timer/TimerTask 内建单线程执行定时任务,如果某个任务执行时间过长,会影响其他任务的执行。另外,DelayQueue 还支持动态添加和移除任务,而 Timer/TimerTask 只能在创建时指定任务。

posted @ 2024-12-11 10:18  捞月亮的小北  阅读(15)  评论(1编辑  收藏  举报