【JUC源码解析】LinkedBlockingQueue
简介
一个基于链表的阻塞队列,FIFO的顺序,head指向的元素等待时间最长,tail指向的元素等待时间最短,新元素从队列尾部添加,检索元素从队列头部开始,队列的容量,默认是Integer#MAX_VALUE。
源码分析
内部类Node
     static class Node<E> {
         E item; // 结点的值
         Node<E> next; // 指向下一个结点
         Node(E x) { // 构造方法
             item = x;
         }
     }
属性
     private final int capacity; // 队列的容量,大小
     private final AtomicInteger count = new AtomicInteger(); // 当前队列里元素的个数
     transient Node<E> head; // 头结点,head.item = null
     private transient Node<E> last; // 尾结点,last.next = null
     private final ReentrantLock takeLock = new ReentrantLock(); // 可重入锁,take元素时,需持有该锁
     private final Condition notEmpty = takeLock.newCondition(); // take锁上的条件,队列空时等待,不空时通知
     private final ReentrantLock putLock = new ReentrantLock(); // 可重入锁,put元素时,需持有该锁
     private final Condition notFull = putLock.newCondition(); // put锁上的条件,队列满时等待,不满时通知
通知方法
     private void signalNotEmpty() { // 通知在take锁上等待的线程
         final ReentrantLock takeLock = this.takeLock;
         takeLock.lock(); // 加锁
         try {
             notEmpty.signal(); // 通知
         } finally {
             takeLock.unlock(); // 释放
         }
     }
     private void signalNotFull() { // 通知在put锁上等待的线程
         final ReentrantLock putLock = this.putLock;
         putLock.lock(); // 加锁
         try {
             notFull.signal(); // 通知
         } finally {
             putLock.unlock(); // 释放
         }
     }
元素入队
     private void enqueue(Node<E> node) { // 队尾入队
         last = last.next = node; // last的next域指向新结点,last后移(指向新加入的结点)
     }
元素出队
     private E dequeue() { // 队首出队
         Node<E> h = head; // 获得头结点
         Node<E> first = h.next; // 活动第一个有效(item != null)结点(head结点的next结点)
         h.next = h; // next域指向自己,帮助GC
         head = first; // head后移
         E x = first.item; // 取得结点值
         first.item = null; // 置空
         return x; // 返回
     }
加锁与释放
     void fullyLock() { // 加锁
         putLock.lock();
         takeLock.lock();
     }
     void fullyUnlock() { // 释放
         takeLock.unlock();
         putLock.unlock();
     }
构造方法
     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); // 初始时,last和head指向一个DUMMY结点
     }
     public LinkedBlockingQueue(Collection<? extends E> c) {
         this(Integer.MAX_VALUE);
         final ReentrantLock putLock = this.putLock;
         putLock.lock(); // 加锁,可见性
         try {
             int n = 0;
             for (E e : c) {
                 if (e == null)
                     throw new NullPointerException(); // 空指针
                 if (n == capacity)
                     throw new IllegalStateException("Queue full"); // 越界
                 enqueue(new Node<E>(e)); // 元素入队
                 ++n; // 递增
             }
             count.set(n); // 设置当前队列里元素的个数
         } finally {
             putLock.unlock(); // 解锁
         }
     }
添加元素
put(E e)
     public void put(E e) throws InterruptedException { // 添加元素
         if (e == null)
             throw new NullPointerException(); // 空指针
         int c = -1;
         Node<E> node = new Node<E>(e); // 创建新结点
         final ReentrantLock putLock = this.putLock; // 获得put锁
         final AtomicInteger count = this.count; // 获得当前元素的个数
         putLock.lockInterruptibly(); // 加锁,响应中断
         try {
             while (count.get() == capacity) { // 队列满了
                 notFull.await(); // 要等一等
             }
             enqueue(node); // 入队
             c = count.getAndIncrement(); // 获取队列的容量
             if (c + 1 < capacity) // 不满,唤醒等待的线程
                 notFull.signal(); // 通知
         } finally {
             putLock.unlock(); // 解锁
         }
         if (c == 0) // 队列非空(c初始值为-1)
             signalNotEmpty();
     }
offer(E e, long timeout, TimeUnit unit)
     public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
         if (e == null)
             throw new NullPointerException(); // 空指针
         long nanos = unit.toNanos(timeout);
         int c = -1;
         final ReentrantLock putLock = this.putLock; // 获得put锁
         final AtomicInteger count = this.count; // 获得当前元素的个数
         putLock.lockInterruptibly(); // 加锁,响应中断
         try {
             while (count.get() == capacity) { // 队列满了
                 if (nanos <= 0) // 超时,返回
                     return false;
                 nanos = notFull.awaitNanos(nanos); // 等待响应的时间
             }
             enqueue(new Node<E>(e)); // 入队
             c = count.getAndIncrement(); // 获取队列的容量
             if (c + 1 < capacity) // 不满,唤醒等待的线程
                 notFull.signal(); // 通知
         } finally {
             putLock.unlock(); // 解锁
         }
         if (c == 0)
             signalNotEmpty(); // 队列非空(c初始值为-1)
         return true;
     }
offer(E e)
     public boolean offer(E e) {
         if (e == null)
             throw new NullPointerException(); // 空指针
         final AtomicInteger count = this.count; // 获得当前元素的个数
         if (count.get() == capacity) // 队列满了,直接返回失败
             return false;
         int c = -1;
         Node<E> node = new Node<E>(e); // 新建结点
         final ReentrantLock putLock = this.putLock; // 获得put锁
         putLock.lock(); // 加锁
         try {
             if (count.get() < capacity) { // 不满
                 enqueue(node); // 入队
                 c = count.getAndIncrement(); // 加1
                 if (c + 1 < capacity) // 不满,通知
                     notFull.signal();
             }
         } finally {
             putLock.unlock(); // 解锁
         }
         if (c == 0)
             signalNotEmpty(); // 不空,通知
         return c >= 0;
     }
获取元素
take()
     public E take() throws InterruptedException {
         E x;
         int c = -1;
         final AtomicInteger count = this.count; // 当前队列元素个数
         final ReentrantLock takeLock = this.takeLock; // 获取take锁
         takeLock.lockInterruptibly(); // 加锁,响应中断
         try {
             while (count.get() == 0) { // 队列空了
                 notEmpty.await(); // 等待
             }
             x = dequeue(); // 出队
             c = count.getAndDecrement(); // 减1
             if (c > 1) // 不空
                 notEmpty.signal(); // 通知
         } finally {
             takeLock.unlock(); // 解锁
         }
         if (c == capacity) // 获取元素之前,队列是满的,有线程在put元素时阻塞,当前线程take一个元素后,空出一个位置
             signalNotFull(); // 通知
         return x;
     }
poll(long timeout, TimeUnit unit)
     public E poll(long timeout, TimeUnit unit) throws InterruptedException {
         E x = null;
         int c = -1;
         long nanos = unit.toNanos(timeout); // 计算等待时间
         final AtomicInteger count = this.count; // 当前队列元素个数
         final ReentrantLock takeLock = this.takeLock; // 获得take锁
         takeLock.lockInterruptibly(); // 加锁,响应中断
         try {
             while (count.get() == 0) { // 队列空了
                 if (nanos <= 0) // 超时
                     return null;
                 nanos = notEmpty.awaitNanos(nanos); // 等待指定时间
             }
             x = dequeue(); // 出队
             c = count.getAndDecrement(); // 个数减1
             if (c > 1) // 非空
                 notEmpty.signal(); // 通知
         } finally {
             takeLock.unlock();
         }
         if (c == capacity) // 同take()方法
             signalNotFull();
         return x;
     }
poll()
     public E poll() {
         final AtomicInteger count = this.count; // 当前队列元素个数
         if (count.get() == 0) // 队列空了,直接返回
             return null;
         E x = null;
         int c = -1;
         final ReentrantLock takeLock = this.takeLock; // 获得take锁
         takeLock.lock(); // 加锁
         try {
             if (count.get() > 0) { // 非空
                 x = dequeue(); // 元素出队
                 c = count.getAndDecrement(); // 个数减1
                 if (c > 1) // 非空,通知
                     notEmpty.signal();
             }
         } finally {
             takeLock.unlock(); // 解锁
         }
         if (c == capacity)
             signalNotFull(); // 同take()方法
         return x;
     }
peek()
     public E peek() { // 只获取元素,不出队
         if (count.get() == 0) // 队列为空,直接返回null
             return null;
         final ReentrantLock takeLock = this.takeLock; // 获得take锁
         takeLock.lock(); // 解锁
         try {
             Node<E> first = head.next; // 取得第一个有效元素
             if (first == null) // 为空,直接返回null
                 return null;
             else
                 return first.item; // 返回结果
         } finally {
             takeLock.unlock(); // 解锁
         }
     }
剔除结点p
     void unlink(Node<E> p, Node<E> trail) { // 剔除结点p
         p.item = null; // 置空
         trail.next = p.next; // 断开p, 连接p的next结点
         if (last == p) // 如果p是尾结点,last指针前移
             last = trail;
         if (count.getAndDecrement() == capacity) // 同take()方法
             notFull.signal();
     }
删除元素
     public boolean remove(Object o) { // 删除元素o
         if (o == null)
             return false;
         fullyLock(); // 加锁
         try { // 从头结点开始遍历,找寻o元素所在的结点,并从中剔除它
             for (Node<E> trail = head, p = trail.next; p != null; trail = p, p = p.next) {
                 if (o.equals(p.item)) {
                     unlink(p, trail); // 剔除
                     return true;
                 }
             }
             return false;
         } finally {
             fullyUnlock(); // 解锁
         }
     }
迁徙
     public int drainTo(Collection<? super E> c, int maxElements) { // 将当前队列里的元素移动到c中,并从当前队列里清除这些元素
         if (c == null)
             throw new NullPointerException(); // 空指针
         if (c == this)
             throw new IllegalArgumentException(); // 不合法参数
         if (maxElements <= 0) // 参数校验
             return 0;
         boolean signalNotFull = false;
         final ReentrantLock takeLock = this.takeLock; // 获得take锁
         takeLock.lock(); // 加锁
         try {
             int n = Math.min(maxElements, count.get()); // 取其中较小值
             Node<E> h = head; // 头结点
             int i = 0; // 初始值
             try {
                 while (i < n) {
                     Node<E> p = h.next; // 取得元素
                     c.add(p.item); // 添加到集合c中
                     p.item = null; // 置空
                     h.next = h; // 结点next域指向自己,帮助GC
                     h = p;  // 元素出队
                     ++i; // 自增
                 }
                 return n; // 返回
             } finally {
                 if (i > 0) {
                     head = h; // 更新头节点
                     signalNotFull = (count.getAndAdd(-i) == capacity); // 需要通知
                 }
             }
         } finally {
             takeLock.unlock(); // 解锁
             if (signalNotFull)
                 signalNotFull(); // 通知
         }
     }
行文至此结束。
尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_lbq.html
【JUC源码解析】LinkedBlockingQueue的更多相关文章
- 【JUC源码解析】ScheduledThreadPoolExecutor
		简介 它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行.在多线程或者对灵活性有要求的环境下,要优于java.util.Timer. 提交的任务在执行之前支 ... 
- 【JUC源码解析】SynchronousQueue
		简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ... 
- 【JUC源码解析】ForkJoinPool
		简介 ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性.对于那种大任务分割小任务的场景(分治)尤其有用. 框架图 ... 
- 【JUC源码解析】DelayQueue
		简介 基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首.只有过期的元素才能出队,在此之前,线程等待. 源码解析 属性 private final transient Reentra ... 
- 【JUC源码解析】CyclicBarrier
		简介 CyclicBarrier,一个同步器,允许多个线程相互等待,直到达到一个公共屏障点. 概述 CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后 ... 
- 【JUC源码解析】ConcurrentLinkedQueue
		简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当 ... 
- 【JUC源码解析】Exchanger
		简介 Exchanger,并发工具类,用于线程间的数据交换. 使用 两个线程,两个缓冲区,一个线程往一个缓冲区里面填数据,另一个线程从另一个缓冲区里面取数据.当填数据的线程将缓冲区填满时,或者取数据的 ... 
- Jdk1.6 JUC源码解析(13)-LinkedBlockingQueue
		功能简介: LinkedBlockingQueue是一种基于单向链表实现的有界的(可选的,不指定默认int最大值)阻塞队列.队列中的元素遵循先入先出 (FIFO)的规则.新元素插入到队列的尾部,从队列 ... 
- Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue
		功能简介: ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列.队列中的元素遵循先入先出(FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素. 和普通队列有所不同,该队列 ... 
随机推荐
- 密码加密MD5,Bash64
			基于jar : org.apache.commons.codec 一.MD5概述:不可逆加密 Message Digest Algorithm MD5(中文名为消息摘要算法第 五版)为计算机安全领域广 ... 
- stylus的用法
			参考链接:预处器的对比——Sass.LESS和Stylus http://www.w3cplus.com/css/sass-vs-less-vs-stylus-a-preprocessor-sho ... 
- Python--BeautifulSoup库安装
			1.BeautifulSoup简介 BeautifulSoup库通过解析文档可以获取网页文档中所需的数据,方便用户从HTML或XHTML文档中提取数据,作为python的一个辅助工作,也是爬虫实践中的 ... 
- ChakraCore ,Net托管编程
			前言 有些有着复杂业务逻辑的应用程序,需要为用户提供高度自定化的功能.比如像Word中的宏,当然可以自己设计一套简易的脚本解析引擎,但考虑通用性,成熟度,其实选择一款JS脚本引擎,直接嵌入到应用系统中 ... 
- sys,os加glob加os.path用法
			1 sys.path是python的搜索模块的路径集,是一个list 打印下大概长这样 C:\Python27\Lib\idlelib C:\Windows\system32\python27.z ... 
- Linux Shell常用技巧(十一)
			二十二. 交互式使用Bash Shell: 1. 用set命令设置bash的选项: 下面为set主要选项的列表及其表述: 选项名 开关缩写 描述 allexport -a 打开此开关, ... 
- Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介
			约定 还记得上版本的第二十四篇的约定嘛?现在出来履行啦~ 为什么要重制? 之前写的专栏都是按照心情写的,在最初的时候笔者什么都不懂,而且文章的发布是按照很随性的一个顺序.结果就是说,大家都看完了,都还 ... 
- sublime Text3安装 markdownediting 报错 解决记录
			看了一下官方文档,也是醉了,都怪自己的无知. 在安装时候不要打开.md的文件,因为你里面有可能有一些语法错误,所以会导致报错. 解决方法关闭其他文件,在重新安装! 官方解释: 参考文档:Trouble ... 
- linux利用sh脚本上传下载文件到ftp服务器
			####本地的/app/awsm/csv2 to ftp服务器上的/awsm/#### #!/bin/sh export today=`date +%Y-%m-%d` ftp -v -n 10.116 ... 
- mybatis中SQL语句运用总结
			union 连接查询 连接两个表后会过滤掉重复的值 <resultMap id="BaseResultMap" type="com.sprucetec.pay.e ... 
