`
wang7839186
  • 浏览: 42056 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

BlockQueue之ArrayBlockingQueue源码解析

阅读更多

前面我们介绍的LinkedBlockingQueue的源码,这篇文章我们一起研究下ArrayBlockingQueue的源码

 

(1)LinkedBlockingQueue源码解析

(2)ArrayBlockingQueue源码解析

 

从语义上看,ArrayBlockingQueue底层是基于数组实现的,而LinkedBlockingQueue底层是基于链表实现的(实际是封装为Node,类似C语言的节点),两者实现方式的不同,也造成了性能和效率的差异。

我们首先来介绍下几个重要的类变量:

 

/**实际承载队列元素的数组 */
    final Object[] items;

    /** 消费者序列号 for next take, poll, peek or remove */
    int takeIndex;

    /**生产者序列号 for next put, offer, or add */
    int putIndex;

    /** 队列大小 */
    int count;

    /*
     * 并发的控制采用两种condition的逻辑,也就是俗称的”两把锁“
     */

    /** Main lock guarding all access */
    final ReentrantLock lock;
    /** 消费者锁 */
    private final Condition notEmpty;
    /** 生产者锁 */
    private final Condition notFull;

 

 

下面看几个核心的私有方法:

 

/**
     * 入队时的核心方法,block内部维护了一个putIndex,用来标示
     * 当前允许插入的下标
     * 一旦插入后,等待notEmpty的线程就被唤醒,即可以消费了
     */
    private void insert(E x) {
        items[putIndex] = x;
        putIndex = inc(putIndex);
        ++count;
        notEmpty.signal();
    }


/**
     * 出对时的核心方法,同insert,block内部维护了takeIndex
     * 用来标示当前允许出对的下标
     * 而一旦出对,等待notFull的线程也被唤醒,即可以生产了
     */
    private E extract() {
        final Object[] items = this.items;
        E x = this.<E>cast(items[takeIndex]);
        items[takeIndex] = null;
        takeIndex = inc(takeIndex);
        --count;
        notFull.signal();
        return x;
    }

 

可见,ArrayBlockingQueue的入队和出对,都是基于数组的实现,而LinkedBlockingQueue则是对元素封装成Node后,再进行其他操作,所以在大量线程操作队列时,ArrayBlockingQueue的性能要优于LinkedBlockingQueue。

 

ArrayBlockingQueue是固定大小的队列,初始化时,必须要传入队列的容量。

 

下面我们列举ArrayBlockingQueue提供的几个队列方法

 

一 offer

 

public boolean offer(E e) {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            if (count == items.length)
                return false;
            else {
                insert(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }

 

offer提供了两个重载的方法,上面的这个是不带参数的,如果当前队列已饱和,则直接返回false,而另一个offer方法中可传入等待时间,如果在指定的等待时间内,仍然等不到队列有空的位置,则直接返回false

 

public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {

        checkNotNull(e);
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length) {
                if (nanos <= 0)
                    return false;
                nanos = notFull.awaitNanos(nanos);
            }
            insert(e);
            return true;
        } finally {
            lock.unlock();
        }
    }

 

二 put

 

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

 

可见put方法在队列饱和时,是阻塞的,除非队列不饱和

 

三 poll和take

 

public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return (count == 0) ? null : extract();
        } finally {
            lock.unlock();
        }
    }


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

 

poll和take类似,不同点在于poll在队列空时,是不阻塞的,但是take会一直阻塞直到队列非空

 

四 peek

 

public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return (count == 0) ? null : itemAt(takeIndex);
        } finally {
            lock.unlock();
        }
    }

 

peek方法只是返回队首元素,但是不移除

 

此外,还提供了一些实用的方法,toArray(将队列转换为数组),clear(清空队列),drainTo(将队列转移到集合中)

1
6
分享到:
评论

相关推荐

    ArrayBlockingQueue源码解析-动力节点共

    在深入理解ArrayBlockingQueue的源码之前,我们需要先了解其基本概念和特性。 ArrayBlockingQueue的核心特点在于其固定大小的容量,这使得它在处理高并发场景时能有效控制资源消耗。队列的元素按照FIFO(先进先出)...

    ArrayBlockingQueue源码分析.docx

    下面我们将深入分析其主要的实现机制、方法以及源码。 1. **数据结构与容量** `ArrayBlockingQueue` 内部使用一个数组 `items` 来存储元素,因此它的容量在创建时就需要指定,且不可改变。这个容量限制确保了队列...

    Java源码解析阻塞队列ArrayBlockingQueue介绍

    Java源码解析阻塞队列ArrayBlockingQueue介绍 Java源码解析阻塞队列ArrayBlockingQueue介绍是Java中的一种阻塞队列实现,使用ReentrantLock和Condition来实现同步和阻塞机制。本文将对ArrayBlockingQueue的源码进行...

    Java源码解析阻塞队列ArrayBlockingQueue常用方法

    本文将深入解析ArrayBlockingQueue的常用方法及其内部实现机制。 ArrayBlockingQueue的核心是一个固定大小的数组`items`,用于存储队列中的元素。此外,它还有3个关键的索引变量:`takeIndex`、`putIndex`和`count`...

    Java源码解析阻塞队列ArrayBlockingQueue功能简介

    Java源码解析阻塞队列ArrayBlockingQueue功能简介 ArrayBlockingQueue是Java中一个重要的阻塞队列实现,它基于数组实现了有界阻塞队列,提供FIFO(First-In-First-Out)功能。该队列的头元素是最长时间呆在队列中的...

    并发容器之ArrayBlockingQueue和LinkedBlockingQueue实现原理详解

    "并发容器之ArrayBlockingQueue和LinkedBlockingQueue实现原理详解" ArrayBlockingQueue和LinkedBlockingQueue是Java并发容器中两个常用的阻塞队列实现,分别基于数组和链表存储元素。它们都继承自AbstractQueue类...

    Java concurrency集合之ArrayBlockingQueue_动力节点Java学院整理

    Java concurrency集合之ArrayBlockingQueue_动力节点Java学院整理,动力节点口口相传的Java黄埔军校

    java并发之ArrayBlockingQueue详细介绍

    Java并发之ArrayBlockingQueue详细介绍 ArrayBlockingQueue是Java并发编程中常用的线程安全队列,经常被用作任务队列在线程池中。它是基于数组实现的循环队列,具有线程安全的实现。 ArrayBlockingQueue的实现 ...

    实战Concurrent-BlockQueue

    《实战Concurrent-BlockQueue》 在Java并发编程领域,`Concurrent-BlockQueue`是一个重要的数据结构,它结合了线程安全与高效性能。本文将深入探讨`ConcurrentLinkedQueue`、`ArrayBlockingQueue`以及`...

    BlockQueue练习

    - `ArrayBlockingQueue`: 基于数组的阻塞队列,有固定大小且线程安全。 - `LinkedBlockingQueue`: 基于链表的阻塞队列,大小可变,初始容量默认为Integer.MAX_VALUE。 - `PriorityBlockingQueue`: 优先级阻塞队列...

    详细分析Java并发集合ArrayBlockingQueue的用法

    Java并发集合ArrayBlockingQueue的用法详解 Java并发集合ArrayBlockingQueue是Java并发集合框架下的一个重要组件,它提供了阻塞队列的实现,用于多线程环境下的并发操作。下面是对ArrayBlockingQueue的用法详解: ...

    26不让我进门,我就在门口一直等!—BlockingQueue和ArrayBlockingQueue.pdf

    —BlockingQueue和ArrayBlockingQueue.pdf” 【描述】:此文档是关于Java并发编程的学习资料,以漫画形式讲解,聚焦于Java并发编程中的核心概念——BlockingQueue接口及其具体实现ArrayBlockingQueue。 【标签】:...

    java中LinkedBlockingQueue与ArrayBlockingQueue的异同

    这两种队列在很多方面都有相似之处,但在实现机制和性能特性上存在一些差异。 **相同点** 1. **接口实现**:两者都是`BlockingQueue`接口的实现,提供了`put`、`take`等阻塞操作,使得生产者线程在队列满时会被...

    JDK1.5线程池源码及详细注释

    在Java并发编程中,线程池(ThreadPoolExecutor)是一个至关重要的工具,它允许开发者有效地管理线程资源,提高系统的...在实际开发中,根据应用的需求和性能指标来定制线程池配置,是优化并发程序性能的关键步骤之一。

    Java可阻塞队列-ArrayBlockingQueue

    在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的Condition实现的,但是JAVA类中提供了这项功能,是ArrayBlockingQueue,  ArrayBlockingQueue是由数组支持的有界阻塞队列,次队列按照FIFO(先进先...

Global site tag (gtag.js) - Google Analytics