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(); }
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(); } }
方法 | 返回或超时返回 | 阻塞 |
插入 | offer(E e) / offer(e, long timeout, TimeUnit unit) | put(E e) |
移除 | poll() / poll()poll(long timeout, TimeUnit unit) | take() |
插入元素
1、offer(E e) / offer(e, long timeout, TimeUnit unit)
offer方法源码
public boolean offer(E e) { checkNotNull(e); final ReentrantLock lock = this.lock; lock.lock(); try { if (count == items.length) return false; else { enqueue(e); return true; } } finally { lock.unlock(); } }
offer方法流程如下
1)先对插入的元素进行非空检查,如果为空checkNotNull方法会抛出异常
2)上锁
3)如果队列已满,返回false表示插入元素失败,否则元素入列,返回true表示插入成功
4)在退出方法前,finally块释放锁
可以看见offer方法在插入过程中保证了线程同步,如果队列已满,会使得插入失败,返回false
offer还有另一个重载方法
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(); } }
这个重载方法多了两个参数,实现的是超时退出,如果队列为满,会使得当前线程进入等待状态等待一定的时长,等待期间如果队列不为满了就会被唤醒,然后元素添加成功,如果超过了参数设置的时限队列仍为满,元素就会添加失败,返回false。
2、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(); } }
put方法流程如下
1)先对插入的元素进行非空检查,如果为空checkNotNull方法会抛出异常
2)上锁
3)如果队列已满,与offer方法不同的是,这里会调用notFull.await()迫使当前线程进入等待并且释放锁,直到队列不满才会被唤醒并且重新获得锁
4)元素入列
5)释放锁
当队列为满时,offer超时退出实现的是等待一定时间,而put方法就可以让当前线程无限等待。在源码中可以看到,如果队列为满,put方法会无限等待下去,直到线程被唤醒,并且当前队列不为满,新的元素才可以入列。
移除元素
1、poll() / poll()poll(long timeout, TimeUnit unit)
poll 两个方法源码如下
public E poll() { final ReentrantLock lock = this.lock; lock.lock(); try { return (count == 0) ? null : dequeue(); } finally { lock.unlock(); } }
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) { if (nanos <= 0) return null; nanos = notEmpty.awaitNanos(nanos); } return dequeue(); } finally { lock.unlock(); } }
poll方法用于元素出列,实现思想类似于offer两个方法,如果队列不为空,队头元素出列,并将其返回。否则返回null,或者等待超时后,如果队列仍为空,返回null。
2、take()
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) notEmpty.await(); return dequeue(); } finally { lock.unlock(); } }
take也是元素出列的方法,如果队列为空,没有元素可以出列时,线程会进入等待状态,直至被唤醒,并且队列不为空了,方法