ArrayBlockingQueue 源码分析

2024-01-10 12:45:10

ArrayBlockingQueue 实际实现是一个环形数组,并且保护了线程安全,那么是如何保证线程安全的?

环形数组怎么实现的?

先看下里面的几个参数是干嘛的

    /** 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;

    /*
     * Concurrency control uses the classic two-condition algorithm
     * found in any textbook.
     */

    /** Main lock guarding all access */
    默认的非公平锁,支持公平锁
    final ReentrantLock lock;

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

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

?ArrayBlockingQueue 实际实现是一个环形数组 先看下它咋实现的

    private void enqueue(E x) {
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        拿到局部变量防止并发
        final Object[] items = this.items;
        将数据放入数组
        items[putIndex] = x;
        如果到头了反回到尾节点
        if (++putIndex == items.length) putIndex = 0;
        真实数量++
        count++;
        非空锁解锁,take方法此时可以继续执行了
        notEmpty.signal();
    }

   /**
     * 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 {
        Objects.requireNonNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            如果数据相等证明满了,锁住不放
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

?offer如果队列满了会抛弃掉,offer方法如果满了会锁住挂起等到加入为止

 public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                如果 == 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;
        数据量-1
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        解锁
        notFull.signal();
        return x;
    }

环形数组示例图片嘛,大概这样

文章来源:https://blog.csdn.net/m0_54010212/article/details/135499315
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。