首页 > 编程语言 >java15源码-ArrayBlockingQueue

java15源码-ArrayBlockingQueue

时间:2022-11-22 16:57:05浏览次数:54  
标签:java15 队列 items 源码 线程 lock put ArrayBlockingQueue

一 阻塞队列API

Throws exception Special value Blocks Times out
Insert add(e) offer(e) put(e) offer(e, time, unit)
Remove remove() poll() take() poll(time, uint)
Examine element() peek()

二 类图

三 构造方法

// ArrayBlockingQueue.java
final Object[] items; // 存放数据元素的数组
int putIndex; // put脚标
int count; // 队列中存放的元素数量

/**
     * ReentrantLock
     *     - 保证多生产者多消费者场景下线程安全
     *     - 通过条件队列实现阻塞/通知模式
     */
    final ReentrantLock lock;

/**
     * ReentrantLock锁的条件队列
     * 队列已经空了就无法继续take元素 让线程阻塞在条件队列上
     * 阻塞在上面的线程只有队列不为空才会被唤醒 有机会继续竞争take元素
     */
    @SuppressWarnings("serial")  // Classes implementing Condition may be serializable.
    private final Condition notEmpty;

/** Condition for waiting puts */
    /**
     * ReentrantLock锁的条件队列
     * 队列已经满了就无法继续put元素 让线程阻塞在条件队列上
     * 阻塞在上面的线程只有队列不满才会被唤醒 有机会继续竞争put元素
     */
    @SuppressWarnings("serial")  // Classes implementing Condition may be serializable.
    private final Condition notFull;

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();
    }

ArrayBlockingQueue使用的数据结构是数组,通过两个指针移动控制元素入队出队,循环往复

阻塞的实现依赖于ReentrantLock的条件队列

四 API

1 put

// ArrayBlockingQueue.java
public void put(E e) throws InterruptedException {
        Objects.requireNonNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await(); // 队列已经满了就把put线程阻塞在条件队列上 等待有其他线程take走元素唤醒put线程
            this.enqueue(e); // 元素入队操作
        } finally {
            lock.unlock();
        }
    }
// ArrayBlockingQueue.java
private void enqueue(E e) { // 元素入队操作
        // assert lock.isHeldByCurrentThread();
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        final Object[] items = this.items;
        items[this.putIndex] = e;
        if (++putIndex == this.items.length) putIndex = 0; // 移动put脚标
        this.count++; // 更新元素数量
        this.notEmpty.signal(); // 尝试唤醒曾经因为队列空了阻塞的take线程
    }

2 take

// ArrayBlockingQueue.java
public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await(); // 队列已经空了就把当前take线程阻塞在ReentrantLock的条件队列上 等待其他线程put元素后唤醒take线程
            return this.dequeue(); // 元素出队
        } finally {
            lock.unlock();
        }
    }
// ArrayBlockingQueue.java
private E dequeue() {
        // assert lock.isHeldByCurrentThread();
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E e = (E) items[takeIndex]; // 取到的元素
        items[takeIndex] = null; // help GC
        if (++takeIndex == items.length) takeIndex = 0; // 移动take脚标
        count--; // 元素数量跟新
        if (this.itrs != null)
            this.itrs.elementDequeued();
        this.notFull.signal(); // 尝试唤醒曾经可能因为队列满了而阻塞的put线程
        return e;
    }

五 总结

ArrayBlockingQueue
数据结构 数组
是否有界 有界,必须指定大小初始化数组
锁实现 ReentrantLock
锁数量 1
线程阻塞机制 ReentrantLock条件队列阻塞/通知唤醒
生产者消费者用锁 共用同一个锁

标签:java15,队列,items,源码,线程,lock,put,ArrayBlockingQueue
From: https://www.cnblogs.com/miss-u/p/16915654.html

相关文章

  • 1、ArrayList源码解析
    目录1概述2底层数据结构3构造函数4自动扩容5set()get()remove()6Fail-Fast机制1概述ArrayList实现了List接口,是顺序容器,允许放入null元素有一个容量(capacit......
  • forsage佛萨奇智能合约2.0源码解析
    本文由威-kaifa873整理发布,仅作为项目开发需求参考!飞机@sleu88TherearefivereasonsforjoiningFosaki:ItisacompletelyfairEthereumsmartcontract.Thefund......
  • 直播网站源码,uni-app 数据上拉加载更多功能
    直播网站源码,uni-app数据上拉加载更多功能打开项目根目录中的pages.json配置文件,为subPackages分包中的商品goods_list页面配置上拉触底的距离:"subPackages":[ ......
  • 下载go源码时,遇到git - error: RPC failed; curl 18 transfer closed with outstandin
    执行下条语句时,出现该错误gitclonehttps://go.googlesource.com/go解决方案:gitconfig--globalhttp.postBuffer524288000......
  • Seata 1.5.2 源码学习(事务执行)
    关于全局事务的执行,虽然之前的文章中也有所涉及,但不够细致,今天再深入的看一下事务的整个执行过程是怎样的。1.TransactionManagerio.seata.core.model.TransactionManag......
  • Android设计模式系列(7)--SDK源码之命令模式
    命令模式,在.net,java平台的事件机制用的非常多,几乎每天都与之打交道。android中对我印象最深的就是多线程多进程的环境,所以必然大量使用到Runbable,Thread,其实用的就是最......
  • Android设计模式系列(1)--SDK源码之组合模式
    Android设计模式系列(1)–SDK源码之组合模式Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用。在androidUI设计,几乎所有的widget和布局类......
  • 从源码的角度探究Activity的启动过程
    一.概述今天我们来搞一下底层一点的东西,大家可能对Activity的生命周期比较熟悉,但是一个Activity是如何启动起来的,你知道吗?今天就来探究一下。二.分析我们先随便写一个demo,然......
  • 从源码的角度理解Android消息处理机制
    总结与Handler共同作用的有Looper,MessageQueue,Message。我么接下来从源码的角度看看整个过程的大概实现。首先说一下每个对象的作用:Looper:消息轮询循器,不断的从消息队......
  • java15源码-ThreadPoolExecutor
    一Executors工具类创建ThreadPoolExecutorSingleThreadExecutornewFixedThreadPoolnewCachedThreadPoolnewScheduledThreadPoolnewSingleThreadScheduledExecuto......