加深一下BlockingQueue的认识

认识BlockingQueue

BlockingQueue是一种可以阻塞线程的队列,java中对这种队列提供了方法抽象,BlockingQueue则是抽象的接口。

  • add:添加元素到队列里,添加成功返回true,由于容量满了添加失败会抛出IllegalStateException异常
  • offer:添加元素到队列里,添加成功返回true,添加失败返回false
  • put:添加元素到队列里,如果容量满了会阻塞直到容量不满
  • poll:删除队列头部元素,如果队列为空,返回null。否则返回元素。
  • remove:基于对象找到对应的元素,并删除。删除成功返回true,否则返回false
  • take:删除队列头部元素,如果队列为空,一直阻塞到队列有元素并删除

参考文章 http://blog.csdn.net/x_i_y_u_e/article/details/52513038

认识一下ArrayBlockingQueue和LinkedBlockingQueue

这两个类是数组与链表的实现,这两个各有特点:

ArrayBlockingQueue

  • 初始化时要指定长度
  • 单个锁控制,读与写共用一个锁
  • 基于array定位查找快

LinkedBlockingQueue

  • 初始化时默认为Integer.MAX_VALUE
  • 使用分离锁,写入时用的putLock,读取时用的takeLock
  • 生产消息的时候需要转换为Node,有性能损耗

阻塞的原理

写时的阻塞

因为写入时阻塞主要是put方法,所以可以通过两个实现类的put方法来看一下是如何实现。

  • ArrayBlockingQueue
public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length)
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}

可以看到这里会获取到一个锁,然后在在入队之前会有一个while,条件是count==item.length,其中count是指的当前队列已经写入的数据项个数,item是用于存数据的一个数组。也就是说如果当前队列的数据项等于数组的长度了,说明已经满了,此时则调用noteFull.await()阻塞当前线程;

  • LinkedBlockingQueue
public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    // Note: convention in all put/take/etc is to preset local var
    // holding count negative to indicate failure unless set.
    int c = -1;
    Node<E> node = new Node<E>(e);
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly();
    try {
        /*
         * Note that count is used in wait guard even though it is
         * not protected by lock. This works because count can
         * only decrease at this point (all other puts are shut
         * out by lock), and we (or some other waiting put) are
         * signalled if it ever changes from capacity. Similarly
         * for all other uses of count in other wait guards.
         */
        while (count.get() == capacity) {
            notFull.await();
        }
        enqueue(node);
        c = count.getAndIncrement();
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();
}

LinkedBlockingQueue在实现put时确实麻烦一些,只不过阻塞的模式是一样的,都是通过判断容易是否已经写满。

读时的阻塞

读时的配对方法是take,这个方法会对读取进行阻塞。

  • LinkedBlockingQueue
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

可以看到原理一样,只不过这里用的是notEmpty这个条件对象,意思表示空的时候等待。

  • LinkedBlockingQueue
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;
}

同理LinkedBlockingQueue的实现也是一样的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户2442861的专栏

C内存管理一 概述

我们写了这么多年的程序员,可能理论方面还比不上大学生。有人 "嘘"我了,如果有能回答以下几个问题的同学请举手: 1.面试经常遇到:同学请说说堆栈的区别? 2....

951
来自专栏程序你好

在c#中,如何序列化/反序列化一个字典对象?

.Net提供的各种序列化的类,通过使用这些类,. Net对象的序列化和反序列化变得很容易。但是字典对象的序列化并不是那么容易。为此,您必须创建一个能够序列化自身...

1051
来自专栏行者常至

015.多线程-并发队列

在并发队列上JDK提供了两套实现, 一个是以ConcurrentLinkedQueue为代表的高性能队列, 一个是以BlockingQueue接口为代表的阻...

1022
来自专栏HTML5学堂

2015.12.14 HTML5真题练习

HTML5学堂:每天一道题,强壮程序员!今日主要涉及12.11,关于函数递归调用题目的解答,以及一道涉及变量类型的题目。 HTML5真题【2015.12.11】...

2984
来自专栏JAVA高级架构

Java 高并发综合

这篇文章是研一刚入学时写的,今天整理草稿时才被我挖出来。当时混混沌沌的面试,记下来了一些并发的面试问题,很多还没有回答。到现在也学习了不少并发的知识,回过头来看...

3636
来自专栏java一日一条

50个常见的 Java 错误及避免方法(第二部分)

System.out.println("Whatdo you want to do?");

1193
来自专栏木头编程 - moTzxx

PHP 只保留字符串首尾字符/隐藏部分字符串

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/de...

1581
来自专栏黑泽君的专栏

【小知识】小例子说明Spring的核心思想之一:控制反转。

目的:改写已存在的类的某个方法或某些方法,使方法增强了。装饰设计模式(也即包装设计模式) 口诀:

1811
来自专栏HTML5学堂

2015.12.04 HTML5真题练习

HTML5学堂:每天一道题,强壮程序员!今日主要涉及昨日题目(计时器、单线程、Date对象知识)的解答,以及一道涉及数据类型、NaN相关知识的题目。 HTML5...

3515
来自专栏java一日一条

Java 高并发综合

这篇文章是研一刚入学时写的,今天整理草稿时才被我挖出来。当时混混沌沌的面试,记下来了一些并发的面试问题,很多还没有回答。到现在也学习了不少并发的知识,回过头来看...

2023

扫码关注云+社区

领取腾讯云代金券