一、概述

  LinkedBlockingQueue是一个单向链表实现的阻塞队列。该队列按 FIFO(先进先出)排序元素,新元素插入到队列的尾部,并且队列获取操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。

  此外,LinkedBlockingQueue还是可选容量的(防止过度膨胀),即可以指定队列的容量。如果不指定,默认容量大小等于Integer.MAX_VALUE。

1.1、原理数据结构

  

说明
  1. LinkedBlockingQueue继承于AbstractQueue,它本质上是一个FIFO(先进先出)的队列。

  2. LinkedBlockingQueue实现了BlockingQueue接口,它支持多线程并发。当多线程竞争同一个资源时,某线程获取到该资源之后,其它线程需要阻塞等待。

  3. LinkedBlockingQueue是通过单链表实现的。

    (01) head是链表的表头。取出数据时,都是从表头head处插入。
    (02) last是链表的表尾。新增数据时,都是从表尾last处插入。
    (03) count是链表的实际大小,即当前链表中包含的节点个数。
    (04) capacity是列表的容量,它是在创建链表时指定的。
    (05) putLock是插入锁,takeLock是取出锁;notEmpty是“非空条件”,notFull是“未满条件”。通过它们对链表进行并发控制。

LinkedBlockingQueue在实现“多线程对竞争资源的互斥访问”时,对于“插入”和“取出(删除)”操作分别使用了不同的锁。对于插入操作,通过“插入锁putLock”进行同步;对于取出操作,通过“取出锁takeLock”进行同步。

此外,插入锁putLock和“非满条件notFull”相关联,取出锁takeLock和“非空条件notEmpty”相关联。通过notFull和notEmpty更细腻的控制锁。

-- 若某线程(线程A)要取出数据时,队列正好为空,则该线程会执行notEmpty.await()进行等待;当其它某个线程(线程B)向队列中插入了数据之后,会调用notEmpty.signal()唤醒“notEmpty上的等待线程”。此时,线程A会被唤醒从而得以继续运行。
此外,线程A在执行取操作前,会获取takeLock,在取操作执行完毕再释放takeLock。
-- 若某线程(线程H)要插入数据时,队列已满,则该线程会它执行notFull.await()进行等待;当其它某个线程(线程I)取出数据之后,会调用notFull.signal()唤醒“notFull上的等待线程”。此时,线程H就会被唤醒从而得以继续运行。
此外,线程H在执行插入操作前,会获取putLock,在插入操作执行完毕才释放putLock。

1.2、示例

/*
* LinkedBlockingQueue是“线程安全”的队列,而LinkedList是非线程安全的。
*
* 下面是“多个线程同时操作并且遍历queue”的示例
* (01) 当queue是LinkedBlockingQueue对象时,程序能正常运行。
* (02) 当queue是LinkedList对象时,程序会产生ConcurrentModificationException异常。
*
*/
public class LinkedBlockingQueueDemo1 { // TODO: queue是LinkedList对象时,程序会出错。
//private static Queue<String> queue = new LinkedList<String>();
private static Queue<String> queue = new LinkedBlockingQueue<String>(); public static void main(String[] args) { // 同时启动两个线程对queue进行操作!
new MyThread("ta").start();
new MyThread("tb").start();
} private static void printAll() {
String value;
Iterator iter = queue.iterator();
while (iter.hasNext()) {
value = (String) iter.next();
System.out.print(value + ", ");
}
System.out.println();
} private static class MyThread extends Thread {
MyThread(String name) {
super(name);
} @Override
public void run() {
int i = 0;
while (i++ < 6) {
// “线程名” + "-" + "序号"
String val = Thread.currentThread().getName() + i;
queue.add(val);
// 通过“Iterator”遍历queue。
printAll();
}
}
}
}

结果说明
示例程序中,启动两个线程(线程ta和线程tb)分别对LinkedBlockingQueue进行操作。以线程ta而言,它会先获取“线程名”+“序号”,然后将该字符串添加到LinkedBlockingQueue中;接着,遍历并输出LinkedBlockingQueue中的全部元素。 线程tb的操作和线程ta一样,只不过线程tb的名字和线程ta的名字不同。
当queue是LinkedBlockingQueue对象时,程序能正常运行。如果将queue改为LinkedList时,程序会产生ConcurrentModificationException异常。

1.3、使用场景

二、源码说明

008-多线程-JUC集合-Queue-LinkedBlockingQueue的更多相关文章

  1. java多线程----JUC集合”01之 框架

    java集合的架构.主体内容包括Collection集合和Map类:而Collection集合又可以划分为List(队列)和Set(集合). 1. List的实现类主要有: LinkedList, A ...

  2. JUC集合之 LinkedBlockingQueue

    LinkedBlockingQueue介绍 LinkedBlockingQueue是一个单向链表实现的阻塞队列.该队列按 FIFO(先进先出)排序元素,新元素插入到队列的尾部,并且队列获取操作会获得位 ...

  3. Java多线程系列--“JUC集合”08之 LinkedBlockingQueue

    概要 本章介绍JUC包中的LinkedBlockingQueue.内容包括:LinkedBlockingQueue介绍LinkedBlockingQueue原理和数据结构LinkedBlockingQ ...

  4. Java多线程系列--“JUC集合”01之 框架

    概要 之前,在"Java 集合系列目录(Category)"中,讲解了Java集合包中的各个类.接下来,将展开对JUC包中的集合进行学习.在学习之前,先温习一下"Java ...

  5. java多线程系类:JUC集合:01之框架

    概要 之前,在"Java 集合系列目录(Category)"中,讲解了Java集合包中的各个类.接下来,将展开对JUC包中的集合进行学习.在学习之前,先温习一下"Java ...

  6. Java多线程系列--“JUC集合”07之 ArrayBlockingQueue

    概要 本章对Java.util.concurrent包中的ArrayBlockingQueue类进行详细的介绍.内容包括:ArrayBlockingQueue介绍ArrayBlockingQueue原 ...

  7. Java多线程系列--“JUC集合”09之 LinkedBlockingDeque

    概要 本章介绍JUC包中的LinkedBlockingDeque.内容包括:LinkedBlockingDeque介绍LinkedBlockingDeque原理和数据结构LinkedBlockingD ...

  8. Java多线程系列--“JUC集合”10之 ConcurrentLinkedQueue

    概要 本章对Java.util.concurrent包中的ConcurrentHashMap类进行详细的介绍.内容包括:ConcurrentLinkedQueue介绍ConcurrentLinkedQ ...

  9. Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList

    概要 本章是"JUC系列"的CopyOnWriteArrayList篇.接下来,会先对CopyOnWriteArrayList进行基本介绍,然后再说明它的原理,接着通过代码去分析, ...

  10. Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet

    概要 本章是JUC系列中的CopyOnWriteArraySet篇.接下来,会先对CopyOnWriteArraySet进行基本介绍,然后再说明它的原理,接着通过代码去分析,最后通过示例更进一步的了解 ...

随机推荐

  1. Scala配置环境变量Linux

    1.下载.上传并解压scala-2.11.6.tgz 2.配置环境变量vim /etc/profile 增加如下代码: export SCALA_HOME=/usr/scala/scala-2.11. ...

  2. Thrift使用入门---RPC服务

    https://blog.csdn.net/zkp_java/article/details/81879577 RPC基本原理 大部分的RPC框架都遵循如下三个开发步骤: RPC通信过程如下图所示 通 ...

  3. 【克鲁斯卡尔蒜法-最小生成树算法】-zzuli-2271 -Problem -E-魔法交流活动

    问题 E: 魔法交流活动 题目描述 魔法学校近日开展了主题为“天气晴朗”的魔法交流活动.N名魔法师按阵法站好,之后选取N - 1条魔法链将所有魔法师的魔力连接起来,形成一个魔法阵.魔法链是做法成功与否 ...

  4. P2161 [SHOI2009]会场预约[线段树/树状数组+二分/STL]

    题目描述 PP大厦有一间空的礼堂,可以为企业或者单位提供会议场地.这些会议中的大多数都需要连续几天的时间(个别的可能只需要一天),不过场地只有一个,所以不同的会议的时间申请不能够冲突.也就是说,前一个 ...

  5. VS Code 常用插件配置

    Debugger for Chrome 该扩展可以在两种模式下运行--它可以启动(launch)导航到你的应用程序的Chrome实例,也可以附加(attach)到正在运行的Chrome实例.这两种模式 ...

  6. CSS定位有几种?分别描述其不同

    static(静态定位):即默认值,元素框正常生成的,top.right.bottom.left这些偏移属性不会影响静态定位的正常显示(属性不应用): relative(相对定位):元素相对自身偏移某 ...

  7. vue 配置 TinyMCE

    1.index.html 增加cdn 地址 <script src="//cdn.bootcss.com/tinymce/5.0.16/tinymce.min.js"> ...

  8. LightOJ - 1179-Josephus Problem(约瑟夫环)

    链接: https://vjudge.net/problem/LightOJ-1179 题意: The historian Flavius Josephus relates how, in the R ...

  9. svn优点跟缺点?

    优点: 1.svn优点:集中式管理,管理方式在服务端配置好,客户端只需要同步提交即可,使用方便,操作简单,很容易就可以上手 2.在服务端统一控制好访问权限,利用代码的安全管理. 3.所有的代码以服务端 ...

  10. MongoDB 分片管理(四)数据均衡

    通常来说,MongoDB会自动处理数据均衡. 1.1 集群分片的块的均衡 注意,均衡器只使用块的数量,而非数据大小,来作为衡量分片间是否均衡的指标. 1.2 均衡器 1.执行所有数据库管理操作前,都应 ...