简介

一个基于链表的阻塞队列,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的更多相关文章

  1. 【JUC源码解析】ScheduledThreadPoolExecutor

    简介 它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行.在多线程或者对灵活性有要求的环境下,要优于java.util.Timer. 提交的任务在执行之前支 ...

  2. 【JUC源码解析】SynchronousQueue

    简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ...

  3. 【JUC源码解析】ForkJoinPool

    简介 ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性.对于那种大任务分割小任务的场景(分治)尤其有用. 框架图 ...

  4. 【JUC源码解析】DelayQueue

    简介 基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首.只有过期的元素才能出队,在此之前,线程等待. 源码解析 属性 private final transient Reentra ...

  5. 【JUC源码解析】CyclicBarrier

    简介 CyclicBarrier,一个同步器,允许多个线程相互等待,直到达到一个公共屏障点. 概述 CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后 ...

  6. 【JUC源码解析】ConcurrentLinkedQueue

    简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当 ...

  7. 【JUC源码解析】Exchanger

    简介 Exchanger,并发工具类,用于线程间的数据交换. 使用 两个线程,两个缓冲区,一个线程往一个缓冲区里面填数据,另一个线程从另一个缓冲区里面取数据.当填数据的线程将缓冲区填满时,或者取数据的 ...

  8. Jdk1.6 JUC源码解析(13)-LinkedBlockingQueue

    功能简介: LinkedBlockingQueue是一种基于单向链表实现的有界的(可选的,不指定默认int最大值)阻塞队列.队列中的元素遵循先入先出 (FIFO)的规则.新元素插入到队列的尾部,从队列 ...

  9. Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue

    功能简介: ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列.队列中的元素遵循先入先出(FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素. 和普通队列有所不同,该队列 ...

随机推荐

  1. 1412. [ZJOI2009]狼和羊的故事【最小割】

    Description “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! O ...

  2. 【[SCOI2010]序列操作】

    好颓啊,我竟然来写了一道恶心的板子 旁边的魏佬嘲讽我,还用欺负我 嘤嘤嘤 那就不膜魏佬了 嘤嘤嘤 这是一道无聊的板子 看到这些操作,我们看到这些操作就知道我们需要维护的东西了 首先那个最长的连续的\( ...

  3. 1、Web Service-开始入坑(基础简介)

    1.关于Schema 具体介绍:https://baike.baidu.com/item/Schema/15286221?fr=aladdin 几个重要的知识点: 2.HTTP协议 具体介绍看博文:h ...

  4. WEB安全 Sqlmap 中绕过空格拦截的12个脚本

    图片较小,可以右键点击图片-->选择 "在新标签中打开图片" --> 查看大图 Sql 注入时遇到过滤空格时可以使用下面12个脚本尝试绕过,在实际利用中可以灵活修改.

  5. jquery mobile各类组件刷新方法

      1.Combobox or select dropdowns var myselect = $("#sCountry"); myselect[0].selectedIndex ...

  6. scrapy(1)win安装

    scrapy是爬虫的一个框架,目前支持python2,python3暂不支持 首先win安装环境: 1.如果你比较幸运,直接pip install scrapy就能成功 2.如果你像我一样,安装过程中 ...

  7. jquery css选择器

    1. $('node+next') == $('node').next() 2. $('node~siblings') == $('node').nextAll(); 3. :gt(index)大于i ...

  8. LeetCode41.缺失的第一个正数 JavaScript

    给定一个未排序的整数数组,找出其中没有出现的最小的正整数. 示例 1: 输入: [1,2,0] 输出: 3 示例 2: 输入: [3,4,-1,1] 输出: 2 示例 3: 输入: [7,8,9,11 ...

  9. PlanetLab介绍

    转自http://blog.sina.com.cn/s/blog_83517c050100vyzq.html PlanetLab产生背景 随着计算机技术和通信技术的不断发展,Internet的商业化和 ...

  10. 01迷宫题解(bfs,联通块)

    题目https://www.luogu.org/problemnew/show/P1141 这个题解主要针对我个人出现的一些问题和注意的地方. 解题思路 首先说一下联通块 联通块这个比较抽象,举个例子 ...