ArrayBlockingQueue源码分析

简述:在jdk concurrent包下面提供了一些同步阻塞队列,这些队列在使用线程池的时候,会把超过核心线程数的任务放在阻塞队列当中,这篇文章主要是来看下ArrayBlockingQueue的源码。

ArrayBlockingQueue是一个线程安全的有界队列,它的主要实现方式是Object[]数组,ReentrantLock,及ReenrantLock中的Condition ,如果对ReentrantLock不熟悉的可以看下之前的博客ReentrantLock实现及AQS简析


从继承体系上来看,满足队列的基本要求,入队列,出队列,属于集合,可以使用Iterater进行遍历,

BlockingQueue除了继承自父接口的一些方法,也提供了对于阻塞队列的一些方法


比如超时的offer, poll等自己的一些方法

下面我们来看ArrayBlockingQueue的基本属性

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
final Object[] items; //用来存储元素的数组
// 下一次执行task,poll,peek或者remove的索引
 int takeIndex;
// 下一次执行put,offer,或者add的索引
 int putIndex;
//当前数组中存放的元素数量
 int count;
// 提供的lock锁
 final ReentrantLock lock;
// 队列空了,就挂起,等到有元素放进去后唤醒
 private final Condition notEmpty;
// 队列满了就挂起,等到取出一个元素后唤醒
 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();
    }

初始化数据长度,设定好是否是公平锁,默认是false,非公平锁

 public ArrayBlockingQueue(int capacity, boolean fair,
                              Collection<? extends E> c) {
        this(capacity, fair);

        final ReentrantLock lock = this.lock;
        lock.lock(); // Lock only for visibility, not mutual exclusion
        try {
            int i = 0;
            try {
                for (E e : c) {
                    checkNotNull(e);
                    items[i++] = e;
                }
            } catch (ArrayIndexOutOfBoundsException ex) {
                throw new IllegalArgumentException();
            }
            count = i;
            putIndex = (i == capacity) ? 0 : i;
        } finally {
            lock.unlock();
        }
    }

这个构造方法在原来的基础上,又增加了一个集合,会将集合当中的元素保存在数组当中,同时修改putIndex的值和count的值

在获取锁这个地方给出了一个注释,锁在这里是保证了可见性,并不是互斥访问,这里加锁是为了让线程将数据写会主存,保证数据的可见性,比如线程A初始化了队列,线程B对队列添加了元素,如果没有加锁,线程A和线程B都没有将数据写回主存,就会造成多线程下,数据错误问题。

关于添加元素操作,有以下几个

add(E e) 队列没有满时,添加元素,满了的话,抛出异常

offer(E e) 没有满添加元素,返回true, 满了的话,返回false

offer(E e, time,unit)  在指定的时间内,插入元素,插入成功返回true, 超过指定时间没有插入元素返回false

put(E e) 如果队列已经满了,一直等待,直到有空余再往里面添加元素

来看下put方法的源码实现

 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();
        }
    }
 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
            putIndex = 0;
        count++;
        notEmpty.signal(); //唤醒阻塞在take上的线程
    }

接下来是关于队列中元素的移除

remove(Object ) 移除队列当中指定元素,如果找到需要移除的元素返回true,否则返回false 

poll() 如果当前没有元素返回null,如果有元素直接取出

poll(time ,unit) 如果没有元素,在等待时间内如果队列中放入元素,取出队列中元素,超过等待时间返回

task() 如果队列中没有元素,一直等待,直到队列中有元素,并且取出队列当中的元素

public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await(); //等待队列中放入元素
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
 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;
    }

以上就是关于ArrayBlockingQueue的分析,如果掌握了ReentrantLock的知识对ArrayBlockingQueue理解起来是比较容易的

如有错误,欢迎指正~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值