深入分析LinkedBlockingQueue
来源:互联网 发布:nginx添加站点 编辑:程序博客网 时间:2024/06/08 04:54
LinkedBlockingQueue是可设置大小的阻塞队列,其内部由链表实现。当为其构造函数传入一个capacity值时,队列的大小就为capacity;否则队列的大小为Integer.MAX_VALUE。
图1 LinkedBlockingQueu的outline
应用场景
LinkedBlockingQueue内部采用链接实现,容量最大可达到Integer.MAX_VALUE。在服务器开发过程中,我们可以将客户端的消息添加到队列中进行异步处理。
源码分析
LinkedBlockingQueue中的链表队列由以下几个内部变量维护:
1、Node节点
static class Node<E> { E item; Node<E> next; Node(E x) { item = x; } }
2、capacity,记录队列允许的大小
private final int capacity;
3、count,记录当前队列中的元素个数
private final AtomicInteger count = new AtomicInteger(0);
4、head、last,头节点和尾节点
/** Head of linked list */ private transient Node<E> head; /** Tail of linked list */ private transient Node<E> last;
5、获取锁及其等待条件
/** Lock held by take, poll, etc */ private final ReentrantLock takeLock = new ReentrantLock(); /** Wait queue for waiting takes */ private final Condition notEmpty = takeLock.newCondition();
6、添加锁及其等待条件
/** Lock held by put, offer, etc */ private final ReentrantLock putLock = new ReentrantLock(); /** Wait queue for waiting puts */ private final Condition notFull = putLock.newCondition();
在ArrayBlockingQueue的实现中,添加和获取元素采用一个ReentrantLock、两个Condition实现,而LinkedBlockingQueue则采用两把锁实现,这样做意味着在添加元素的同时可以获取元素。
构造函数:
public LinkedBlockingQueue() { this(Integer.MAX_VALUE); } public LinkedBlockingQueue(int capacity) { if (capacity <= 0) throw new IllegalArgumentException(); this.capacity = capacity; last = head = new Node<E>(null); } public LinkedBlockingQueue(Collection<? extends E> c) { this(Integer.MAX_VALUE); final ReentrantLock putLock = this.putLock; putLock.lock(); // Never contended, but necessary for visibility try { int n = 0; for (E e : c) { if (e == null) throw new NullPointerException(); if (n == capacity) throw new IllegalStateException("Queue full"); enqueue(e); ++n; } count.set(n); } finally { putLock.unlock(); } }
在LinkedBlockingQueue(Collection
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); int c = -1; final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; putLock.lockInterruptibly(); try { // 队列已满,阻塞当前线程 while (count.get() == capacity) { notFull.await(); } // 添加到队列中 enqueue(e); c = count.getAndIncrement(); // 取操作允许同时进行 // 此处可找机会唤醒其他等待添加元素的线程 if (c + 1 < capacity) notFull.signal(); } finally { putLock.unlock(); } // 如果c为0,那么就有可能存在阻塞的获取操作的线程 // 此处唤醒可能存在的获取操作的线程 if (c == 0) signalNotEmpty(); }
相比ArrayBlockingQueue,LinkedBlockingQueue的put()方法增加了更多的额外操作。由于LinkedBlockingQueue中的获取和添加由不同的锁控制,因此在队列不为空且不满的情况下,读取操作可以同时进行。此时在添加完一个元素后,可以判断count的大小,以找机会唤醒其他等待添加或获取元素的线程。
take()方法:
public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); try { // 队列为空,则阻塞当前线程 while (count.get() == 0) { notEmpty.await(); } // 获得元素 x = dequeue(); c = count.getAndDecrement(); // 添加操作允许同时进行 // 此处可找机会唤醒其他等待获取元素的线程 if (c > 1) notEmpty.signal(); } finally { takeLock.unlock(); } // 如果c为capacity,那么就有可能存在阻塞的添加操作的线程 // 此处唤醒可能存在的添加操作的线程 if (c == capacity) signalNotFull(); return x; }
take()方法的逻辑和put()方法相似,只是判断条件正好相反。因此不在具体分析。
ArrayBlockingQueue和LinkedBlockingQueue的比较
相同点:
在功能使用上,两个阻塞队列有相似点,都可以设定大小,put()和take()方法都能完成阻塞功能。
不同点:
1、通过分析其源代码可以看到,ArrayBlockingQueue内部采用数组实现,LinkedBlockingQueue内部采用链表实现,因此LinkedBlockingQueue的remove()操作会比ArrayBlockingQueue更快。
2、LinkedBlockingQueue内部的读和取操作采用不同的锁控制,因此可以同时进行。而ArrayBlockingQueue内的读和取操作采用同一把锁控制,在同一个时刻只能进行读操作或取操作。
综上可以看到,在通常情况下,LinkedBlockingQueue的性能会比ArrayBlockingQueue更加好,而且ArrayBlockingQueue有的功能LinkedBlockingQueue都有。因此在实际使用过程中,LinkedBlockingQueue通常都是一个更好的选择。
- 深入分析LinkedBlockingQueue
- LinkedBlockingQueue源码分析
- Java LinkedBlockingQueue 分析
- 源码分析-LinkedBlockingQueue
- LinkedBlockingQueue源码分析
- LinkedBlockingQueue 实现原理分析
- LinkedBlockingQueue源码分析
- LinkedBlockingQueue源码分析
- LinkedBlockingQueue源码分析
- 并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法&&&&SynchronizedMap和ConcurrentHashMap的深入分析
- 深入理解阻塞队列(三)——LinkedBlockingQueue源码分析
- Java LinkedBlockingQueue和ArrayBlockingQueue分析
- Java LinkedBlockingQueue和ArrayBlockingQueue分析 .
- Java LinkedBlockingQueue和ArrayBlockingQueue分析
- java源码分析09-LinkedBlockingQueue
- LinkedBlockingQueue源码分析(JDK8)
- 推荐:LinkedBlockingQueue 实现原理分析
- 阻塞队列LinkedBlockingQueue源码分析
- EventBus粘性事件
- 成长点滴
- SparkContext主要组成部分
- 有关c++对象模型的几个小问题
- 使用XmlPullParser
- 深入分析LinkedBlockingQueue
- Maven实战之旅第二篇——配置maven
- 前端、js基础
- jetty基本架构
- Guibs 的 Python学习_字符串
- HDOJ 3664 Permutation Counting / UVALive 5092 DP
- Java NIO系列教程(一) Java NIO 概述
- 【转】【書評】1984──喬治‧歐維爾
- ConcurrentHashMap原理