一、什么是阻塞队列:
阻塞队列(BlockingQueue)是一种特殊的队列,它在插入和移除元素时支持阻塞操作。具体来说,当队列为空时,尝试从队列中获取元素的线程会被阻塞,直到队列中有元素为止;而当队列满时,尝试向队列中添加元素的线程也会被阻塞,直到队列中有空位为止。
阻塞队列的主要特点包括:
-
先进先出(FIFO)原则:阻塞队列遵循先进先出的原则,即最早插入的元素最先被移除。
-
阻塞机制:在队列为空或满的情况下,阻塞队列会阻塞相应的线程,直到条件满足。例如,当队列为空时,获取元素的线程会被阻塞,直到有元素加入;当队列为满时,插入元素的线程会被阻塞,直到有元素被移除。
-
线程安全:阻塞队列通常用于多线程环境中的生产者-消费者模型,通过阻塞机制平衡生产者和消费者之间的执行速度,避免因线程间的直接通信而导致的死锁或同步问题。
-
多种实现:Java中提供了多种阻塞队列的实现,如
ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue等。这些实现各有特点,例如ArrayBlockingQueue是基于数组的有界队列,而LinkedBlockingQueue是基于链表的可选有界或无界队列。 -
常用方法:阻塞队列提供了多种方法来操作队列,如
put()、take()、offer()、poll()等。这些方法在队列满或空时分别有不同的行为,比如抛出异常、返回特定值、一直阻塞或超时退出。 -
应用场景:阻塞队列广泛应用于需要控制并发执行的任务或进程之间的通信场景,特别是在生产者-消费者模型中,通过阻塞队列可以有效地管理生产者和消费者之间的数据交换。
阻塞队列通过其独特的阻塞机制,在多线程编程中提供了一种有效的同步和通信方式,确保了线程的安全性和数据的一致性。
今天这篇文章为大家带来ArrayBlockingQueue和LinkedBlockingQueue的源常用方法的实现和源码解析
二、ArrayBlockingQueue和LinkedBlockingQueue的差异
-
队列大小:
- ArrayBlockingQueue是有界队列,必须在创建时指定容量大小。
- LinkedBlockingQueue可以是有界或无界的。如果未指定容量,默认为Integer.MAX_VALUE,即无界队列。但也可以指定队列大小,使其成为有界的。
-
数据存储容器:
- ArrayBlockingQueue基于数组实现,使用固定大小的数组来存储元素。
- LinkedBlockingQueue基于链表实现,使用Node节点作为链表连接对象。
-
锁机制:
- ArrayBlockingQueue使用一个全局锁来控制对队列的访问,生产者和消费者共享同一把锁,这可能导致线程竞争。
- LinkedBlockingQueue使用两把独立的锁:putLock用于添加操作,takeLock用于移除操作。这种分离的锁机制提高了并发性能,因为生产者和消费者可以同时进行操作。
-
内存占用:
- ArrayBlockingQueue在创建时需要预先分配内存,即使队列为空也会占用一定的内存空间。
- LinkedBlockingQueue动态分配内存,根据元素的增加而逐渐占用内存空间,因此在处理大量数据时可能对垃圾回收(GC)有较大影响。
-
吞吐量和并发性能:
- 在高并发场景下,LinkedBlockingQueue通常比ArrayBlockingQueue具有更高的吞吐量和并发性能,因为它能够更好地利用多核处理器的优势。
- ArrayBlockingQueue由于锁的竞争,在某些情况下可能会降低性能。
-
公平策略:
- ArrayBlockingQueue支持公平策略,可以维护阻塞线程的顺序,避免线程饥饿问题。
- LinkedBlockingQueue不支持公平策略,通常采用非公平锁。
三、ArratBlockingQueue
常见的将数据放入到队列中的方法:
//add()方法,如果满了直接抛出异常
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
//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();
}
}
//没有参数的offer方法
public boolean offer(E e) {
//还是检查数据的合法性
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
//如果满了直接返回
if (count == items.length)
return false;
else {
//将数据放入,返回true
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
ArrayBlockingQueue的取数据操作:
//remove()方法:
public E remove () {
//直接使用方法pull
E x = poll();
if (x != null)

2241

被折叠的 条评论
为什么被折叠?



