BlockingQueue阻塞队列原理解析

java实现BlockingQueue接口的队列解析 java实现BlockingQueue接口的队列解析阻塞队列与非阻塞队列一个最大的区别就是:阻塞队列能够阻塞当前试图从队列中获取元素的线程,而非阻塞队列不会。因此在面对类似消费者-生产者的模型时,使用非阻塞队列就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦。但是有了阻塞队列就不一样了,它会对当前线程产生阻塞,比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有 阅读详情

BlockingQueue,什么鬼,刚开始接触到这个数据结构的时候,从字面意义上根本没看出这个的意思,怎么会有个block冠在前边,感觉是个不太好的词。但是又发现其在某些服务任务框架上经常使用。今天我们来探秘下这个数据结构的用法。

BlockingQueue源码分析

首先,打开JDK的源码,找到BlockingQueue这个数据结构。(android开发要安装的jdk 1.8,在其安装目录即有源码)。

package java.util.concurrent;

import java.util.Collection;
import java.util.Queue;

 * @since 1.5
 * @author Doug Lea
 * @param <E> the type of elements held in this collection
 */
public interface BlockingQueue<E> extends Queue<E> {

首先,一个数据结构,包名是java.util.concurrent,很显然,这是java为并发操作设计的数据结构。并且还import了Collection和Queue。 所以其当然也有这两个数据结构的特性。而BlockingQueue是个interface接口类型,那这就不是一个真实的可以对象化的类。如同List 是ArrayList<>()的父类,我们初始化时经常用new ArrayList<>()创建对象并赋值给List<>类型的变量一样。他们都是泛型类,数据类型E可以在使用时具体制定。
接下来我们分析这个接口的主要方法。

/**
     * Inserts the specified element into this queue if it is possible to do
     * so immediately without violating capacity restrictions, returning
     * {@code true} upon success and throwing an
     * {@code IllegalStateException} if no space is currently available.
     * ……
     * /
     boolean add(E e);

从注释看出,add方法可以插入数据到队列中,如果队列满了,则抛出IllegalStateException异常。
之后的方法是offer(E e),其和add方法的不同之处在于,前者在队列满时是异常,后者是返回false,而add只是抛出异常。
而下一个方法,就可以看出BlockingQueue的精髓所在,即阻塞。

   /**
     * Inserts the specified element into this queue, waiting if necessary
     * for space to become available.
     *
     * @param e the element to add
     * @throws InterruptedException if interrupted while waiting
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this queue
     * @throws NullPointerException if the specified element is null
     * @throws IllegalArgumentException if some property of the specified
     *         element prevents it from being added to this queue
     */
    void put(E e) throws InterruptedException;

put的精髓就在于,当队列满的时候,会阻塞住,等有空间时插入。

/**
     * Retrieves and removes the head of this queue, waiting if necessary
     * until an element becomes available.
     *
     * @return the head of this queue
     * @throws InterruptedException if interrupted while waiting
     */
    E take() throws InterruptedException;

反之, 队列的取元素也有阻塞方法,如果队列中有元素,则取出处理,否则队列为空时则阻塞等待。
这里只看了上述方法的注释,其他的都是些辅助方法。
由于BlockingQueue只是个接口,只有定义的方法,但是没有实际的实现,即如何实现阻塞,是在实现类中实现的。

其实现类有ArrayBlockingQueue、BlockingDeque等,详细的如下图所示。
BlockingQueue实现类
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

我们分别分析ArrayBlockingQueue和BlockingDeque的源码。

ArrayBlockingQueue源码分析

这里不会分析所有的方法,只捡重要的变量和方法进行分析。
首先是类的声明和变量。

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    /** The queued items */
    final Object[] items;

    /** items index for next take, poll, peek or remove */
    int takeIndex;

    /** items index for next put, offer, or add */
    int putIndex;

    /** Number of elements in the queue */
    int count;
    /** Main lock guarding all access */
    final ReentrantLock lock;

    /** Condition for waiting takes */
    private final Condition notEmpty;

    /** Condition for waiting puts */
    private final Condition notFull;

    /**
     * Shared state for currently active iterators, or null if there
     * are known not to be any.  Allows queue operations to update
     * iterator state.
     */
    transient Itrs itrs = null;

其中的items数组,即要添加的队列数据,有取数据的takeIndex和添加数据的putIndex。还有可重入锁lock。
其构造函数显示,队列的长度是外部传入的,即这个类的对象创建的时候,其大小就确定了。同时确定了lock为非公平锁。

 /**
     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
     * capacity and default access policy.
     *
     * @param capacity the capacity of this queue
     * @throws IllegalArgumentException if {@code capacity < 1}
     */
    public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }
    ……
    public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);
    notEmpty = lock.newCondition();
    notFull =  lock.newCondition();
    }

然后分析其不会阻塞的的offer方法。首先获取lock的引用,并上锁,之后对数据进行操作,如果能正常插入数据,则返回true,否则返回false,最后再finally中unlock。

 /**
     * Inserts the specified element at the tail of this queue if it is
     * possible to do so immediately without exceeding the queue's capacity,
     * returning {@code true} upon success and {@code false} if this queue
     * is full.  This method is generally preferable to method {@link #add},
     * which can fail to insert an element only by throwing an exception.
     *
     * @throws NullPointerException if the specified element is null
     */
    public boolean offer(E e) {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            if (count == items.length)
                return false;
            else {
                enqueue(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }

最主要我们要分析的方法是,这个BlockingQueue如何实现阻塞的。接下来查看put方法的实现。

/**
     * Inserts the specified element at the tail of this queue, waiting
     * for space to become available if the queue is full.
     *
     * @throws InterruptedException {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
    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();
        }
    }

这里的lockInterruptibly什么意思呢。我们在源码的注释中加入中文注释。

Acquires the lock unless the current thread is
     * {@linkplain Thread#interrupt interrupted}.
     * 如果当前线程被打断,则立即获取锁。
     * <p>Acquires the lock if it is not held by another thread and returns
     * immediately, setting the lock hold count to one.
     *如果当前锁未被其他线程持有,则立即获取锁,并设置锁持有数为1
     * <p>If the current thread already holds this lock then the hold count
     * is incremented by one and the method returns immediately.
     *如果当前线程已持有这个锁,则持有锁的数目加1,并立即返回。
     * <p>If the lock is held by another thread then the
     * current thread becomes disabled for thread scheduling
     * purposes and lies dormant until one of two things happens:
     *如果当前锁被另外线程持有,然后当前线程被线程调度为不可运行,则当前线程处于休眠状态,直到  1,锁被当前线程持有  2,其他线程打断了此线程。
     * <ul>
     *
     * <li>The lock is acquired by the current thread; or
     *
     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
     * current thread.
     *
     * </ul>
     *
     * <p>If the lock is acquired by the current thread then the lock hold
     * count is set to one.
     * 如果当前线程获取锁,则将锁持有数设为1
     * …其他注释省略

这里我们了解了这个锁的特性,然后代码
while (count == items.length)
notFull.await();
表示如果队列满了,则等待。一个锁对象可以有一个或多个相关的条件对象,用newCondition方法获取一个条件对象。notFull就是这样一个对象,可以回头看ArrayBlockingQueue的构造方法中,notFull = lock.newCondition();
**如果这个条件变量notFull调用了await()方法,则当前线程阻塞,并且释放锁。**这样,另外的线程就可以拿到锁,并取走队列中的数据,并通知当前线程有了剩余空间,线程被唤醒并添加数据到队列。究竟是不是这样呢,接下来我们找一个取数据的方法 take进行分析。

public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
    /**
     * Extracts element at current take position, advances, and signals.
     * Call only when holding lock.
     */
    private E dequeue() {
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        notFull.signal();
        return x;
    }

从上面的代码看出,首先我们不分析取数据时数据为空导致的阻塞,其和数据满时的锁操作时一致的,我们还是假设刚才数据已满,获取锁,并且取出一个数据,则调用dequeue方法。取出锁之后,**notFull.signal();这个方法的意思是随机解除等待集中某个线程的阻塞状态。**和signal对应的方法是signalAll,意思是解除等待线程的阻塞,即通知所有等待线程,并通过竞争获得锁。 和signal,signalAll对应的有synchronized的notify和notifyAll的区别。可以想见,LinkedBlockingQueue也是类似原理实现阻塞,只不过不是array数组,而是单链表,且由于其可同时头部取数据,尾部添加数据,所以其数据结构中有两把锁,和两个条件变量。还有个原子类型的AtomicInteger类型的count,保证长度数据的原子性。这里不再详细分析,有需要的可以自己查看源码学习。
系统中有很多使用阻塞队列的例子,如系统Tts播放音频时的播放队列。

class AudioPlaybackHandler {
    private static final String TAG = "TTS.AudioPlaybackHandler";
    private static final boolean DBG = false;

    private final LinkedBlockingQueue<PlaybackQueueItem> mQueue =
            new LinkedBlockingQueue<PlaybackQueueItem>();

经过上边的分析我们已经知道了BlockingQueue的实现阻塞的原理。

BlockingDeque的源码分析

deque,双端队列,和queue的区别是。。。。看源码吧
Deque的源码注释是:一个线性组合,支持在两头插入或者移除。**deque是double end queue的简称,原来如此,就是队列queue只能first in last out,即头部出,尾部进。 但是deque即可以头部插入和移除,尾部也可以插入或移除。
/

  • A linear collection that supports element insertion and removal at
  • both ends. The name deque is short for “double ended queue”
  • and is usually pronounced “deck”. Most {@code Deque}
  • implementations place no fixed limits on the number of elements
  • they may contain, but this interface supports capacity-restricted
  • deques as well as those with no fixed size limit.

由于其也是个接口,deque的接口方法有
void addFirst(E e);
void addLast(E e);
boolean offerFirst(E e);
boolean offerLast(E e);
E removeFirst();
E removeLast();
E pollFirst();
E pollLast();
。。。。。
相当于queue有的方法,他都有两份,即first的操作和last的操作。废话少说,开始BlockingDeque的源码分析,由于
public interface BlockingDeque extends BlockingQueue, Deque {
其继承了BlockingQueue和Deque,所以其有这两个数据结构的共同特性。

而再查找BlockingDeque的实现类时,我在SDK中只找到一个实现类,即
LinkedBlockingDeque。刚开始还想不分析LinkedBlockingQueue,这里就来了 LinkedBlockingDeque。
首先其内部泛型类Node,即节点的声明。其中包含一个数据项item和prev方法和next方法。其他为LinkedBlockingDeque的内部变量和锁的声明。

static final class Node<E> {
        /**
         * The item, or null if this node has been removed.
         */
        E item;

        /**
         * One of:
         * - the real predecessor Node
         * - this Node, meaning the predecessor is tail
         * - null, meaning there is no predecessor
         */
        Node<E> prev;

        /**
         * One of:
         * - the real successor Node
         * - this Node, meaning the successor is head
         * - null, meaning there is no successor
         */
        Node<E> next;

        Node(E x) {
            item = x;
        }
    }
 /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

    /** Number of items in the deque */
    private transient int count;

    /** Maximum number of items in the deque */
    private final int capacity;

    /** Main lock guarding all access */
    final ReentrantLock lock = new ReentrantLock();

    /** Condition for waiting takes */
    private final Condition notEmpty = lock.newCondition();

    /** Condition for waiting puts */
    private final Condition notFull = lock.newCondition();

既然是链表实现,那么其中方法也就是链表数据项的的添加和删除

 /**
     * Links node as first element, or returns false if full.
     */
    private boolean linkFirst(Node<E> node) {
        // assert lock.isHeldByCurrentThread();
        if (count >= capacity)
            return false;
            //下边三步即是把新添加的node添加到队头,并且将first赋值为对头的node
        Node<E> f = first;
        node.next = f;
        first = node;
        if (last == null)
            last = node;
        else
            f.prev = node;
        ++count;
        notEmpty.signal();
        return true;
    }
    /**
     * @throws NullPointerException {@inheritDoc}
     * @throws InterruptedException {@inheritDoc}
     */
    public void putFirst(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        final ReentrantLock lock = this.lock;
        //添加数据到队头,并获取锁
        lock.lock();
        try {
        //如果队列满了,则返回false,就会发生阻塞,并释放锁。
            while (!linkFirst(node))
                notFull.await();
        } finally {
            lock.unlock();
        }
    }
     public E takeFirst() throws InterruptedException {
     //从对头取走元素,并获取锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E x;
            //如果对头取出数据为空,则发生阻塞,否则,返回取出的元素
            while ( (x = unlinkFirst()) == null)
                notEmpty.await();
            return x;
        } finally {
            lock.unlock();
        }
    }

从上述源码可以看出,**如果由于队列满导致put数据阻塞,则会释放锁,然后等有takefirst或其他从对头取数据的方法调用后,会在unlinkFirst方法中调用notFull.signal(); 则通知上次putFirst的notFull.await()唤醒,在while方法中判断,插入数据到队头。**队尾操作也是相同的模式。

总结

使用阻塞队列,多线程操作共同的队列时不需要额外的同步。在经典的生产者-消费者模型中,队列会自动平衡负载,即任意一边(生产与消费)处理快了就会被阻塞掉,从而减少两边的处理速度差距,自动平衡负载这个特性就造成它能被用于多生产者队列,因为你生成多了(队列满了)你就要阻塞等着,直到消费者消费使队列不满你才可以继续生产。

参考线平滑-FemPosDeviation-SQP 使用SQP(顺序二次规划)对离散点进行平滑 阅读详情

相关推荐

BOM 数据模型设计

字段名数据类型必填说明物料编码 (Part Number)字符串是唯一标识,主键。建议包含分类前缀(如STD-GEN-CUS-物料名称 (Part Name)字符串是版本 (Revision)字符串是如AB1.0,与编码组合构成唯一实例。状态 (Status)枚举是设计中(Draft)已发布(Released)已归档(Archived)已作废(Obsoleted)类型 (Type)枚举是专用件(Custom)借用件(Borrowed)通用件(Generic)标准件(Standard)

Davina_yu的博客 1756

基于C++11实现的阻塞队列(BlockQueue)

当缓冲区满的时候,生产者会进入阻塞状态,当下次消费者开始消耗缓冲区的数据时,生产者才会被唤醒,开始往缓冲区中添加数据;当缓冲区空的时候,消费者也会进入阻塞状态,直到生产者往缓冲区中添加数据时才会被唤醒。因为要实现线程安全的函数,所以将pop函数的接口设计为需要放入一个自己的T item作为删除数据的拷贝。生产者不会在缓冲区满的时候继续向缓冲区放入数据,而消费者也不会在缓冲区空的时候,消耗数据。1、析构函数:清理队列中的所有成员,唤醒所有阻塞中的生产者、消费者线程。2、生产者线程应该调用的函数。

weixin_50437588的博客 4739

2025年度工业级3D全景相机技术解析选型参考:国产品牌的技术突围与市场格局

本文分析了工业级3D相机在智慧城市和建筑数字化中的应用。通过对比国内外主流设备的技术参数和应用场景,发现国产品牌如众趣科技在性价比和本地化服务方面具有优势,尤其适合大型空间扫描项目;而国际品牌如Faro、Leica则在精度和可靠性上保持领先。建议根据项目需求(如测距范围、精度要求、预算)进行设备选型,综合考虑扫描效率、数据处理能力和系统兼容性。国产品牌已在国内大型基建项目中展现出竞争力,国际品牌则更适合高精度逆向工程和国际化项目。

gxdtgsy的博客 1072

面试刷题11-13

大华8月份投的提前批简历,然后等了快1个月,9月初接到大华一个部门电话,说看重简历上C++项目(本人做Java),然后聊了几下,接着邀约9曰5号去大华面试。9月5号如约而至,果然如网上所说在食堂面试,首先是给1个小时时间做笔试,由于他们是C++客户端方向,试卷全是Linux、C++,还好本人大学及研一做过C++,所以基本能完成。紧接着面试官看过卷子后来面试,一面是关于C++基础的,然后如何优化试卷...

wwxy1995的博客 1822

【一】PCIe基础知识

Linux PCIe基础知识

他山之石 可以攻玉 4万+

Frida实战:SSL Pinning绕过技术全解析

本文详细解析了如何使用Frida工具绕过SSL Pinning技术,包括环境搭建、四种实战绕过方案及常见问题排查指南。通过具体代码示例和实战经验,帮助安全研究人员快速掌握SSL Pinning绕过技术,适用于金融类App的安全测试场景。

weixin_42530732的博客 188

阻塞队列BlockingQueue

阻塞队列 阻塞:必须要阻塞、不得不阻塞 阻塞队列有两个附加操作 支持阻塞的插入方法,当队列满时,从队列中插入元素会被阻塞,直至队列不满 支持阻塞的移除方法,当队列为空时,获取元素的线程会等待队列变为非空 试图从空的队列中获取元素的线程将会被阻塞,直到其他的线程往空队列里插入元素。 试图向已满的队列中添加元素的线程将会被阻塞,知道其他线程从已满的队列中移除元素。 应用场景 常用于生产者与消费者模式中,生产者是向队列里添加元素的线程,消费者是向队列里移除元素的线程。简单来说,阻塞队列是生产者用

Al_0922的博客 368

嵌入式软件面试常见问题及答案

干了多年的嵌入式,被面试过,也面过不少新人,下面这些是面试中很常见的一些问题及答案,答案可以根据自己的经验自己思考下。--持续补充并更新

weixin_37553721的博客 6023

阻塞队列之ArrayBlockingQueue源码分析

BlockingQueue是一个阻塞队列,在高并发场景应用的非常广泛,最常见的情景应该就是在线程池中,其他的比如在ZooKeeper源码中,dubbo源码中也大量使用了阻塞队列,我们经常使用的也就是ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue,ConcurrentLinkedQueue这几种。ArrayBlockingQueueAr...

Niulx 603

PADS VX2.7学习记录06-PADS Router软件功能操作

PADS VX2.7学习记录06-PADS Router软件功能操作

qq_31444421的博客 7860

保姆级教程:用CH34xSerCfg工具修改USB转串口芯片的VID/PID,避免驱动冲突

本文详细介绍了如何使用CH34xSerCfg工具修改USB转串口芯片的VID/PID,解决驱动冲突问题。通过实战案例和配置技巧,帮助开发者高效管理嵌入式设备,避免常见的USB设备识别问题,提升开发效率。

weixin_30924239的博客 224

BlockingQueue(阻塞队列)

目录 1 简介 2 常用方法 入队 出队 3 BlockingQueue的实现 3.1 ArrayBlockingQueue 3.1.1 put方法 3.1.2 take方法 3.2 LinkedBlockingQueue 3.2.1 put方法 3.2.2 take方法 3.2.3 ArrayBlockingQueue与LinkedBlockingQueue对比 3.3 LinkedBlockingDeque 3.4 PriorityBlockingQueue 3.4.1 p

mocas_wang的博客 2230

【局部规划模块曲线算法】曲线平滑介绍

本文先对轨迹平滑问题做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容(1)适合给移动机器人运动的路径【满足运动学,高阶平滑】(2)高阶的运动学不能够突变的【至少三阶的加速度不能突变,最好四阶的jerk和五阶的snap也不能突变】(3)在转弯的地方不会停下来(4)加减速均衡,节省能量(5)节省时间的。

qq_35635374的博客 5715

Java阻塞队列BlockingQueue原理解析

阻塞队列 (BlockingQueue)是Java util.concurrent包下重要的数据结构,BlockingQueue提供了线程安全的队列访问方式:当阻塞队列插入数据时,如果队列已满,线程将会阻塞等待直到队列非满;从阻塞队列取数据时,如果队列已空,线程将会阻塞等待直到队列非空。并发包下很多高级同步类的实现都是基于BlockingQueue实现的。

qq_45061342的博客 1740

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

深入解析阻塞队列(BlockingQueue):原理、实现与面试实战

阻塞队列本质上是一个有界缓冲区,可以用生产者-消费者模型建模:text生产者速率(λ)→ [缓冲区(容量C)] → 消费者速率(μ)稳态条件:λ < μ(否则队列会无限增长)关键公式(M/M/1队列模型):text平均队列长度 = ρ / (1 - ρ),其中 ρ = λ/μ平均等待时间 = ρ / (μ - λ)实际意义当λ接近μ时,队列长度和等待时间会指数级增长这就是为什么需要有界队列——防止系统进入不稳定状态text阻塞队列 = 线程安全队列 + 阻塞机制│。

2503_92804185的博客 365

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

阻塞队列BlockingQueue解析

阻塞队列是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除的方法。抛出异常:当队列满时候插入元素的时候则会直接抛出异常,为空时取出元素也会抛出元素。返回特殊值:这种方式不会阻塞线程而是直接返回boolean类型的值表示是否插入成功或者移除成功一直阻塞:插入或者移除的操作不满足条件的时候会进行阻塞放入Condition的队列中直到满足条件后被唤醒超时退出:进行阻塞是含有时间限制的,超出时间之后线程则会退出方法,返回boolean类型的值JDK 7 提供了 7 个阻塞队列,如下。

qq_65779957的博客 1114

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

阻塞队列 BlockingQueue 我也不会啊

阻塞队列BlockingQueueBlockingQueue中有哪些方法,为什么这样设计?BlockingQueue是怎么实现的? BlockingQueue中有哪些方法,为什么这样设计? 参考答案 为了应对不同的业务场景,BlockingQueue 提供了4 组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每组方法的表现是不同的。这些方法如下: - 抛异常 特定值 阻塞 超时 插入 add(e) offer(e) put(e) offer(e, t

韩旭051的博客 526

BlockingQueue阻塞队列及其实现

转自:https://www.jianshu.com/p/7b2f1fa616c6 1. 前言 BlockingQueue即阻塞队列,它是基于ReentrantLock,依据它的基本原理,我们可以实现Web中的长连接聊天功能,当然其最常用的还是用于实现生产者与消费者模式,大致如下图所示: 在Java中,BlockingQueue是一个接口,它的实现类有ArrayBlockingQueue、DelayQueue、 LinkedBlockingDeque、LinkedBlockingQueue、Pr

渣渣 989

Java线程池(三)之阻塞队列BlockingQueue详解

阻塞队列BlockingQueue(又叫工作队列,又叫任务队列)(在线程池的构造函数中的第五个参数,用于存放待处理的任务,待分配给线程) 里面装的不是线程哦,是元素,例如生产者-消费者中,阻塞队列装的是产品,这里的阻塞队列可以理解成仓库 线程是阻塞队列的操纵者,从里面取或往里面放。当使用put(e)、take()时,线程才会被阻塞,但也不是放进BlockingQueue中。 在线程池里面,工作队列(也即阻塞队列)里面装的是代办业务,而不是线程,ok?OK! 队列的接口结构: Lis..

weixin_37695911的博客 2629

BlockingQueue与Condition原理解析

 我在前段时间写了一篇关于AQS源码解析的文章AbstractQueuedSynchronizer超详细原理解析 ,在文章里边我说JUC包中的大部分多线程相关的类都和AQS相关,今天我们就学习一下依赖于AQS来实现的阻塞队列BlockingQueue的实现原理。本文中的源码未加说明即来自于以ArrayBlockingQueue。 阻塞队列  相信大多数同学在学习线程池时会了解阻塞队列的概念,熟记各...

weixin_34018202的博客 325

并发编程-10阻塞队列BlockingQueue

使用线程池的肯定对阻塞队列的肯定不陌生,阻塞队列的的阻塞功能是如何实现的?常见的阻塞队列和他们的使用场景是哪些?在项目中我们应该如何选择合适的阻塞队列呢?本篇将从源码开始分析各个阻塞队列的底层数据结构和原理,这样更容易让我们在系统中选择合适的阻塞队列!

落雪 707

Java 阻塞队列--BlockingQueue

在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利。

小飞侠的博客 1040

Java并发之BlockingQueue源码解析

首先来说BlockingQueue是什么?从字面上来看,BlockingQueue就是阻塞队列,它是一个先进先出且线程安全的队列。那么它什么时候发生阻塞?有两种情况: 队列已满时进行入队操作,这个时候会阻塞,等待队列中的元素出队 队列为空时进行出队操作,这个时候也会阻塞,等待有元素入队 BlockingQueue适用于生产者-消费者的场景。生产者不断地生产对象丢到BlockingQueue中(入队),直到BlockingQueue爆满。生产者线程会阻塞,等待消费者消费对象。而消费者不断地从Blockin

Epoch_Elysian的博客 471

BlockingQueue及其实现

1. 前言 BlockingQueue即阻塞队列,它是基于ReentrantLock,依据它的基本原理,我们可以实现Web中的长连接聊天功能,当然其最常用的还是用于实现生产者与消费者模式,大致如下图所示: 在Java中,BlockingQueue是一个接口,它的实现类有ArrayBlockingQueue、DelayQueue、 LinkedBlockingDeque、LinkedBlo...

b_just的博客 2685

Java阻塞队列

背景 阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除方法 1)支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满。 2)支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空 阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。 在阻塞队列不可用时,这两个附加操作提供了4种处理方式 抛出异

渣渣 495

三、线程安全阻塞队列 BlockingQueue 详解

转载自: https://www.cnblogs.com/WangHaiMing/p/8798709.html 本篇将详细介绍BlockingQueue,以下是涉及的主要内容: BlockingQueue的核心方法 阻塞队列的成员的概要介绍 详细介绍DelayQueue、ArrayBlockingQueue、LinkedBlockingQueue的原理 线程池与BlockingQueue 1、...

日拱一卒 7107
上一篇: 五分钟读懂Android中的Binder跨进程机制和AIDL工具
下一篇: 深入浅出AsyncTask的工作原理
Zephyr Cai
博客等级 码龄18年 39粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值