阻塞队列 (BlockingQueue) 的实现原理?
阻塞队列使用Lock+多个Condition实现的FIFO的队列 。 多线程环境下安全的, 如果队列满了, 放入元素的 线程会被阻塞, 如果队列空了, 取元素的线程会被阻塞 。 具体原理一起看源代码。
JDK 7提供了7个阻塞队列, 如下。
·ArrayBlockingQueue: 一个由数组结构组成的有界阻塞队列。
· LinkedBlockingQueue: 一个由链表结构组成的有界阻塞队列。
· PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列。
· DelayQueue: 一个使用优先级队列实现的无界阻塞队列。
·SynchronousQueue: 一个不存储元素的阻塞队列。
· LinkedTransferQueue: 一个由链表结构组成的无界阻塞队列。
· LinkedBlockingDeque: 一个由链表结构组成的双向阻塞队列。
ArrayBlockingQueue是一个用数组实现的有界阻塞队列 。此队列按照先进先出 (FIFO) 的原则对元素进行排序。 默认情况使用的是非公平锁。
LinkedBlockingQueue是一个用链表实现的有界阻塞队列 。此队列的默认和最大长度为 Integer.MAX_VALUE 。此队列按照 先进先出的原则对元素进行排序。
PriorityBlockingQueue是一个支持优先级的无界阻塞队列 。默认情况下元素采取自然顺序 升序排列 。也可以自定义类实 现compareTo()方法来指定元素排序规则, 或者初始化 PriorityBlockingQueue时, 指定构造参数Comparator来对元素进行 排序。
DelayQueue是一个支持延时获取元素的无界阻塞队列 。 队列使用PriorityQueue来实现 。 队 列中的元素必须实现Delayed 接口, 在创建元素时可以指定多久才能从队列中获取当前元素 。 只有在延迟期满时才能从队列中提取元素。
SynchronousQueue是一个不存储元素的阻塞队列 。 每一个put操作必须等待一个take操作, 否则不能继续添加元素 。 它 支持公平访问队列 。默认情况下线程采用非公平性策略访问队列 。 队列本身并不存储任何元素, 非常适合传递性场景 。 SynchronousQueue的吞吐量高于 LinkedBlockingQueue和ArrayBlockingQueue。
LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列 。相对于其他阻 塞队列 , LinkedTransferQueue多了tryTransfer和transfer方法 。 如果当前有消费者正在等待接收元素 (消费者使用take()方法或带时 间限制的poll()方法 时) , transfer方法可以把生产者传入的元素立刻transfer (传输) 给消费者 。 如果没有消费者在等 待 接收元素, transfer方法会将元素存放在队列的tail节点, 并等到该元素被消费者消费了才返 回 。tryTransfer方法是用来试 探生产者传入的元素是否能直接传给消费者 。 如果没有消费者等 待接收元素, 则返回false 。 和transfer方法的区别是 tryTransfer方法无论消费者是否接收, 方法 立即返回, 而transfer方法是必须等到消费者消费了才返回。
LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列 。所谓双向队列指的是可以 从队列的两端插入和 移出元素 。双向队列因为多了一个操作队列的入口, 在多线程同时入队 时, 也就减少了一半的竞争 。相比其 他的阻塞队列, LinkedBlockingDeque多了addFirst 、 addLast 、 offerFirst 、 offerLast 、 peekFirst和peekLast等方 法, 以First单词结尾的方法, 表示插入 、 获取 (peek) 或移除双端队列的第一个元素 。 以Last单词结尾的方 法, 表示插入 、 获取或移除双 端队列的最后一个元素。
在初始化LinkedBlockingDeque时可以设置容量防止其过度膨胀 。 另外, 双向阻塞队列可以 运用在“工作窃取” 模式中。