你使用过 Java 中的哪些阻塞队列?
你使用过 Java 中的哪些阻塞队列?
回答重点
阻塞队列主要用来阻塞队列的插入和获取操作,当队列满了的时候插入操作会被阻塞,直到队列有空位。当队列为空的时候获取操作会被阻塞,直到队列有值。
常用在实现生产者和消费者场景,在笔试题中比较常见。
常见的阻塞队列包括:
- ArrayBlockingQueue:一个有界队列,底层基于数组实现。需要在初始化时指定队列的大小,队列满时,生产者会被阻塞,队列空时,消费者会被阻塞。
- LinkedBlockingQueue:基于链表的阻塞队列,允许可选的界限(有界或无界)。无界模式下可以不断添加元素,直到耗尽系统资源。有界模式则类似于
ArrayBlockingQueue,但吞吐量通常较高。 - PriorityBlockingQueue:一个无界的优先级队列,元素按照自然顺序或者指定的比较器顺序进行排序。与其他阻塞队列不同的是,PriorityBlockingQueue 不保证元素的 FIFO 顺序。
- DelayQueue:一个无界队列,队列中的元素必须实现
Delayed接口,只有当元素的延迟时间到期时,才能被取出。常用于延迟任务调度。 - SynchronousQueue:一个没有内部容量的队列,每个插入操作必须等待对应的移除操作,反之亦然。常用于在线程之间的直接传递任务,而不是存储任务。
扩展知识
使用场景
- ArrayBlockingQueue 和 LinkedBlockingQueue 常用于典型的生产者-消费者场景。例如:任务处理系统中,生产者生成任务,消费者从队列中取出任务并执行。
- PriorityBlockingQueue 更适合处理带有优先级的任务场景,如任务调度系统。
- DelayQueue 适用于需要延迟处理的任务,例如:缓存失效策略、定时任务调度等。
- SynchronousQueue 适合在线程间直接传递数据,而不希望数据被存储在队列中。例如:
ThreadPoolExecutor的直接交接模式中使用 SynchronousQueue 来传递任务。
ArrayBlockingQueue 和 LinkedBlockingQueue 区别
常见的有 ArrayBlockingQueue 和 LinkedBlockingQueue,分别是基于数组和链表的有界阻塞队列。
两者原理都是基于 ReentrantLock 和 Condition 。
ArrayBlockingQueue 基于数组,内部实现只用了一把锁,可以指定公平或者非公平锁。
LinkedBlockingQueue 基于链表,内部实现用了两把锁,take 一把、put 一把,所以入队和出队这两个操作是可以并行的,从这里看并发度应该比 ArrayBlockingQueue 高。
LinkedTransferQueue
LinkedTransferQueue,相对于其他阻塞队列从名字来看它有 Transfer 功能,其实也不是什么神奇功能,一般阻塞队列都是将元素入队,然后消费者从队列中获取元素。
而 LinkedTransferQueue 的 transfer 是元素入队的时候看看是否已经有消费者在等了,如果有在等了直接给消费者即可,所以就是这里少了一层,没有锁操作。
Comments