JUC源码分析-集合篇(九):LinkedBlockingQueue

LinkedBlockingQueue 是单向链表结构的自定义容量的阻塞队列,元素操作按照FIFO(first-in-first-out 先入先出)的顺序,使用显式锁 ReentrantLock 和 Condition 来保证线程安全。链表结构的队列通常比基于数组的队列(ArrayBlockingQueue)有更高的吞吐量,但是在并发环境下性能却不如数组队列。因为比较简单,本章本来是不在笔者的写作范围内的,但是在后面的线程池源码中用到了LinkedBlockingQueue,我们我们就来简单看一下,加深一下印象。

本章应该是队列篇的终章了,还有LinkedBlockingDeque、ArrayBlockingQueue这些比较简单的队列就不再讲解了,后面我们会开始线程池相关源码分析。


概述

LinkedBlockingQueue(后称LBQ)队列容量可通过参数来自定义,并且内部是不会自动扩容的。如果未指定容量,将取最大容量Integer.MAX_VALUE。 如果你理解了前几篇我们所讲的队列,那么你会发现 LBQ 非常容易理解,内部没有太多复杂的算法,数据结构也是使用了简单的链表结构。


数据结构

LinkedBlockingQueue 继承关系

标准的队列继承关系,不多赘述。

重要属性
//容量
private final int capacity;

//元素个数
private final AtomicInteger count = new AtomicInteger();

//链表头
transient Node<E> head;

//链表尾
private transient Node<E> last;

//出列锁
private final ReentrantLock takeLock = new ReentrantLock();

//等待获取(出队)条件
private final Condition notEmpty = takeLock.newCondition();

//入列锁
private final ReentrantLock putLock = new ReentrantLock();

//等待插入(入列)条件
private final Condition notFull = putLock.newCondition();

LBQ 在实现多线程对竞争资源的互斥访问时,对于入列和出列操作分别使用了不同的锁。对于入列操作,通过putLock进行同步;对于出列操作,通过takeLock进行同步。
此外,插入锁putLock和出列条件notFull相关联,出列锁takeLock和出列条件notEmpty相关联。通过notFullnotEmpty更细腻的控制锁。

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

源码解析

put(E e)

LBQ 的添加元素的方法有offer()、put()put是在队列已满的情况下等待,而offer则直接返回结果,它们内部操作都一致。所这里我们只对put进行解析

//尾部插入节点,队列满时会一直等待可用,响应中断
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;//获取入列锁
    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)
        signalNotEmpty();
}

说明:看源码吧。

poll()

LBQ 的获取元素的方法有poll()、take()、peek()take在队列为空的情况下会一直等待,poll不等待直接返回结果,peek是获取但不移除头结点元素,内部操作都差不多。这里我们只对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();
    }
    if (c == capacity)
        signalNotFull();
    return x;
}

说明:略。。。

小结

本章只是为了加深同学们的印象,为之后线程池源码解析做准备,随便看看就行了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容