ArrayBlockingQueue是什么
ArrayBlockingQueue是最典型的有界阻塞队列。
内部使用数组存储元素!
初始化时需要指定容量大小。
利用 ReentrantLock 实现线程安全!
ArrayBlockingQueue的适用场景
在生产者-消费者模型中使用时,如果生产速度和消费速度基本匹配的情况下,可以使用ArrayBlockingQueue。
当如果生产速度远远大于消费速度,则会导致队列填满,大量生产线程被阻塞。
ArrayBlockingQueue的实现原理
使用独占锁ReentrantLock实现线程安全,入队和出队操作使用同一个锁对象,也就是只能有一个线程可以进行入队或者出队操作;
意味着生产者和消费者无法并行操作,在高并发场景下会成为性能瓶颈。
ArrayBlockingQueue的特点
有界队列!先进先出!存取互相排斥!
使用的数据结构是静态数组:容量固定,没有扩容机制;没有元素的位置也占用空间,被 null 占位;
使用ReentrantLock锁:存取是同一把锁,操作的是同一个数组对象,存取互相排斥。
ArrayBlockingQueue的入队出队操作
两个指针都是从队首向队尾移动,保证队列的先进先出原则!
入队阻塞对象notFull:队列count=length,放不进去元素时,阻塞在该对象上。
出队阻塞对象notEmpty:队列count=0,无元素可取时,阻塞在该对象上。
入队操作:从队首开始添加元素,记录putIndex(到队尾时设置为0),唤醒notEmpty。
出队操作:从队首开始取出元素,记录takeIndex(到队尾时设置为0),唤醒notFull。
ArrayBlockingQueue的使用方式
BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue <Integer>(1000 );
System.out.println(blockingQueue.add(9 ));
blockingQueue.put(10 );
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
ArrayBlockingQueue的数据结构源码分析
final Object[] items;
int takeIndex;
int putIndex;
int count;
final ReentrantLock lock;
private final Condition notEmpty;
private final Condition notFull;
ArrayBlockingQueue的构造方法源码分析
public ArrayBlockingQueue (int capacity) {
this (capacity, false );
}
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();
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();
}
}
ArrayBlockingQueue的入队方法:put(E e) 源码分析
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) {
final Object[] items = this .items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0 ;
count++;
notEmpty.signal();
}
public void lockInterruptibly () throws InterruptedException {
sync.acquireInterruptibly(1 );
}
public final void acquireInterruptibly (int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException ();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
private void doAcquireInterruptibly (int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true ;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null ;
failed = false ;
return ;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException ();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
public final void signal () {
if (!isHeldExclusively())
throw new IllegalMonitorStateException ();
Node first = firstWaiter;
if (first != null )
doSignal(first);
}
private void doSignal (Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null )
lastWaiter = null ;
first.nextWaiter = null ;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null );
}
ArrayBlockingQueue的出队方法:take() 源码分析
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 () {
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;
}
结束语
获取更多本文的前置知识文章,以及新的有价值的文章,让我们一起成为架构师!
关注公众号,可以让你对MySQL有非常深入的了解
关注公众号,每天持续高效的了解并发编程!
关注公众号,后续持续高效的了解spring源码!
这个公众号,无广告!!!每日更新!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构