ArrayBlockingQueue

ArrayBolckingQueue

  ArrayBlockingQueue是一个用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序。
  ArrayBlockingQueue内部只有一把锁,就是说同一时刻只能有一个线程可以进行put或者take操作。
  默认情况下不保证线程公平的访问队列,所谓公平访问队列是指阻塞的线程,可以按照阻塞的先后顺序访问队列,即先阻塞线程先访问队列。非公平性是对先等待的线程是非公平的,当队列可用时,阻塞的线程都可以争夺访问队列的资格,有可能先阻塞的线程最后才访问队列。为了保证公平性,通常会降低吞吐量;

1、继承关系

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable 

2、属性

注意:

  • items的大小需要在构造ArrayBlockingQueue时进行指定,因为数组前有final修饰,无法扩容,创建之后数组的大小无法再改变;
  • 在ArrayBlockingQueue中队列元素个数count为int类型,因为同一时刻只能有一个线程对底层的数组进行put或者take操作,所以不用担心count会被其他线程修改,而在LinkedBlockingQueue中,队列元素的个数count为AtomicInteger类型,在LinkedBlockingQueue中会有提到。
	//items是用来存储元素的数组,ArrayBlockingQueue底层是用数组来实现的
    final Object[] items;

	//读取操作的位置
    int takeIndex;

	//写操作的位置
	int putIndex;

	//队列里元素的个数
	int count;

	//队列同步相关属性,在构造函数中进行初始化
    final ReentrantLock lock;  //重入锁
    //重入锁的两个Condition实例,用于并发
    private final Condition notEmpty; 
    private final Condition notFull;

3、构造函数

public ArrayBlockingQueue(int capacity) {
    //通过capacity来初始化阻塞队列的大小,默认为非公平性锁
    this(capacity, false);
}


//通过capacity来初始化阻塞队列的大小,fair用来设置锁是公平性锁还是非公平性锁
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
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();
     }
}

4、put() 添加元素

  在队列已满时,调用put()方法的线程会调用notFull.await释放锁进入阻塞状态,如果有另一个线程移除了一个数据,就会调用notFull.signal,这时上一个进行put操作的线程可能被释放从而获取锁,执行完put()方法将元素添加到队列里;

    public void put(E e) throws InterruptedException {
        checkNotNull(e); //ArrayBlockingQueue不能存储null值
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly(); //显性添加可中断锁
        try {
            while (count == items.length) { //当前容量满了之后处于await状态,在take操作中会给当前发送消息
                notFull.await();
            }
            insert(e);
        } finally {
            //显性释放锁
            lock.unlock();
        }
    }
    
=====================================
	
    private void insert(E x) {
        items[putIndex] = x; //在数组的putIndex位置插入元素
        putIndex = inc(putIndex);
        ++count; //数组中元素的个数+1,因为
        //作用于take操作中,阻塞队列中没有元素时的await状态
        notEmpty.signal();
    }

5)take() 删除元素

  在队列为空时,调用take()方法的线程会调用notEmpty.await,释放锁进入阻塞状态,若有另一个执行put操作的线程添加了一个元素,就会重新调用notEmpty.signal,这时上面执行take操作的线程就可能被释放,获取锁之后会将take操作执行完毕;

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock; //获取锁
    lock.lockInterruptibly(); //添加可中断锁
    try {
        while (count == 0) { //若队列为空则阻塞当前线程
            notEmpty.await();
        }
        return extract(); //队列不为空时,返回移除的元素
    } finally {
        lock.unlock(); //释放锁
   } 
}

============================

private E extract() {
    final Object[] items = this.items;
    E x = this.<E>cast(items[takeIndex]); //拿出takeIndex位置的元素
    items[takeIndex] = null; //将该位置置为null
    takeIndex = inc(takeIndex);
    --count;
    //作用于put操作中,队列满时的await状态
    notFull.signal();
    return x; //返回被移除的元素
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值