BlockingQueue之ArrayBlockingQueue


ArrayBlockingQueue

基于数组的阻塞队列,底层数据结构为定长的数组,实例化的时候必须指定数组的长度

1 核心参数

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
		
    /** 存储数据的数组 */
    final Object[] items;

    /** 队头指针,当前可以获得元素的下标*/
    int takeIndex;

    /** 队尾指针,当前可以存储元素的下标
    	* 当队列满时putIndex=0
    	*/
    int putIndex;

    /** 当前队列中的数据总数 */
    int count;
  
    /** 全局可重入锁,用来控制队列中元素的操作 */
    final ReentrantLock lock;

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

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

    /**
     * Shared state for currently active iterators, or null if there
     * are known not to be any.  Allows queue operations to update
     * iterator state.
     */
    transient Itrs itrs = null;
  
  	................
}

2 构造方法

    /**
     * 创建一个指定长度的队列, 非公平锁
     
     * @param capacity 指定的队列长度
     */
    public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }

    /**
     * 创建指定长度和指定是否公平的队列
     
     * @param capacity 指定的队列长度
     * @param fair 是否公平: true: 遵循现在先出的原则, false
     * @throws IllegalArgumentException if {@code capacity < 1}
     */
    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();
    }

    /**
     * 根据给定的长度、是否公平和集合数组创建队列
     * 当集合长度大于capacity 则抛出异常
     * @param capacity 指定的队列长度
     * @param fair 是否公平: true: 遵循现在先出的原则, false
     * @param c 给定的集合长度
     */
    public ArrayBlockingQueue(int capacity, boolean fair,
                              Collection<? extends E> c) {
      this(capacity, fair);
      .......
    }

3 核心方法

添加数据基本流程如下

  • add(E e)

    添加指定数据到队列,成功返回true, 失败抛出IllegalStateException异常,add底层调用的是offer

    // 底层调用的是 offer()
		public boolean add(E e) {
        return super.add(e);
    }

    public boolean add(E e) {
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

  • offer(E e)

    添加指定数据到队列,成功返回true, 失败返回 false

    public boolean offer(E e) {
        checkNotNull(e);
      	// 获得锁
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
          	// 如果队列满了就直接返回false
            if (count == items.length)
                return false;
            else {
              	// 真正添加数据
                enqueue(e);
                return true;
            }
        } 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;
      	// 总数+1
        count++;
      	// 添加元素后,同时通知唤醒在等待的消费者
        notEmpty.signal();
    }

  • offer(E e, long timeout, TimeUnit unit)

    指定等待时间添加数据,该方法和offer(E e)方法基本一致,但是也有以下的不同之处

    • 添加的锁是可中断锁
    • 在等待时间内可以被中断
  /**
  	* @param e 				添加的元素
  	*	@param timeout 	等待时间
  	* @param unit			等待时间单位
  	*/
	public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {

        checkNotNull(e);
    		// 计算需要等待的毫秒值
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
    		// 添加可中断锁
        lock.lockInterruptibly();
        try {
          	
            while (count == items.length) {
              	// 循环等待,直到满足等待时间
                if (nanos <= 0)
                    return false;
                nanos = notFull.awaitNanos(nanos);
            }
            enqueue(e);
            return true;
        } finally {
            lock.unlock();
        }
    }

获取数据的基本流程如下图

  • put(E e)

    添加指定数据到队列,如果队列满了,则阻塞当前线程,直到抛出InterruptedException异常

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

    取出队列的头部的元素,获取不到返回null

    public E poll() {
      	// 拿到锁
        final ReentrantLock lock = this.lock;
      	// 添加普通锁
        lock.lock();
        try {
            return (count == 0) ? null : dequeue();
        } finally {
          	// 释放锁
            lock.unlock();
        }
    }

    /**
     * 真正的从队列中取数据
     */
    private E dequeue() {
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
      	// 数据数组
        final Object[] items = this.items;
        // 获得数据,并把当前位置设置为null
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
      	// +1后的队尾指针如果等于数组长度,说明数组已经到尾部了
      	// 需要从头再开始存放数据
        if (++takeIndex == items.length)
            takeIndex = 0;
      	// 总数-1
        count--;
        if (itrs != null)
            itrs.elementDequeued();
      	// 非满条件通知唤醒生产者可以生产数据了
        notFull.signal();
        return x;
    }

  • poll(long timeout, TimeUnit unit)

    取出队列的头部的元素,如果没有元素则等待指定时间直到成功,获取不到返回null
    等到过程中断线程则抛出InterruptedExcepution

	/**
  	*	@param timeout 	等待时间
  	* @param unit			等待时间单位
  	*/
	public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    		// 计算等待毫秒值
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
    		// 添加可中断锁
        lock.lockInterruptibly();
        try {
            while (count == 0) {
              	// 超过等待时长,直接返回null
                if (nanos <= 0)
                    return null;
                nanos = notEmpty.awaitNanos(nanos);
            }
            return dequeue();
        } finally {
          	// 释放锁
            lock.unlock();
        }
    }
  • take()

    取出队列的头部的元素,如果没有元素则一直等待直到成功
    等到过程中断线程则抛出InterruptedExcepution

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
      	// 可中断锁
        lock.lockInterruptibly();
        try {
          	// 如果为null, 则一直等待,直到被生产线程唤醒
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
          	// 释放锁
            lock.unlock();
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值