Java并发Concurrent包——ArrayBlockingQueue源码分析

ArrayBlockingQueue 是一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。
BlockingQueue 接口实现的都是阻塞队列。而 ConcurrentLinkedQueue 是基于 CAS 和链表实现的无阻塞高性能队列。
ConcurrentLinkedQueue 的源码分析见 Java并发Concurrent包——ConcurrentLinkedQueue源码分析

这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。

属性

    // 底层对象数组
    final Object[] items;

    // 出队的下标
    int takeIndex;

    // 入队的下标
    int putIndex;

    // 元素个数
    int count;

    // 锁对象,控制所有访问
    final ReentrantLock lock;

    // 出队的condition
    private final Condition notEmpty;

    // 入队的condition
    private final Condition notFull;

    // 迭代器
    transient Itrs itrs = null;

构造函数

列出一个最主要的构造函数来分析:

    public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        // 初始化底层数组
        this.items = new Object[capacity];
        // 新建公平或非公平锁,和两个condition
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

重要方法

offer(E e)

    public boolean offer(E e) {
        // 判断对象不为null
        checkNotNull(e);
        // 锁对象
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
            if (count == items.length)
                // 如果数组已经满了,不能再入队
                return false;
            else {
                // 调用enqueue方法,下面分析
                enqueue(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }

enqueue(E x)

    // 只在当前线程拥有锁的时候调用
    private void enqueue(E x) {
        final Object[] items = this.items;
        // 在入队下标处放入新元素
        items[putIndex] = x;
        // 下标加1后,判断是否等于数组总长度,如果是将putIndex置为0
        if (++putIndex == items.length)
            putIndex = 0;
        // 有效元素个数加1
        count++;
        // 唤醒其他基于此condition的线程
        notEmpty.signal();
    }

poll()

    public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 有效元素不为0就可以调用dequeue方法出列
            return (count == 0) ? null : dequeue();
        } finally {
            lock.unlock();
        }
    }

dequeue()

    // 只在当前线程拥有锁的时候调用
    private E dequeue() {
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        // 保存出队下标处的元素
        E x = (E) items[takeIndex];
        // 将该下标处置为null
        items[takeIndex] = null;
        // 如果也走到尽头,从0开始
        if (++takeIndex == items.length)
            takeIndex = 0;
        // 有效元素个数减1
        count--;
        // 
        if (itrs != null)
            itrs.elementDequeued();
        // 队列不再满,发信号给其他线程
        notFull.signal();
        // 返回出队的对象
        return x;
    }

take()

获取并移除此队列的头部,在元素变得可用之前一直等待(如果有必要)。

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            // 如果可用元素为空,则等待notEmpty这个condition的信号
            // 直到出现不为空时,进行出队操作
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

put(E e)

将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间。和 take 方法对应。

    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            // 如果元素已满,则线程阻塞等待出现notFull的情况,才能入队
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

该类的代码比较简单易懂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值