ArrayBlockingQueue的实现原理
时间: 2023-11-30 17:27:53 浏览: 47
`ArrayBlockingQueue` 是一个阻塞式队列,它的实现基于数组。它通常用于多线程环境下的数据共享,可以保证线程安全。
`ArrayBlockingQueue` 维护了一个数组来存储队列中的元素,以及两个指针 `head` 和 `tail` 分别指向队列头和队列尾的位置。当一个元素被放入队列时,`tail` 指针向后移动一个位置;当一个元素被取出队列时,`head` 指针向后移动一个位置。队列满时,无法再放入元素,此时生产者线程将被阻塞,等待队列中的元素被取走;队列空时,无法再取出元素,此时消费者线程将被阻塞,等待队列中的元素被放入。
`ArrayBlockingQueue` 的实现使用了 ReentrantLock 来保证线程安全,并使用了 Condition 来实现线程的阻塞与唤醒。当队列满时,生产者线程会调用 `notFull.await()` 方法等待队列未满;当队列空时,消费者线程会调用 `notEmpty.await()` 方法等待队列非空。当队列中的元素被取走或者被放入时,都会调用 `notFull.signal()` 或者 `notEmpty.signal()` 方法唤醒等待的线程。
需要注意的是,在多线程环境下,当多个线程同时进行插入和删除操作时,可能会导致死锁或者饥饿现象。因此,使用 `ArrayBlockingQueue` 时需要避免出现这种情况。
相关问题
ArrayBlockingQueue
ArrayBlockingQueue是一个由数组实现的有界阻塞队列。它的大小是固定的,由构造函数中指定的容量决定。ArrayBlockingQueue内部使用了重入锁ReentrantLock和Condition条件队列来实现阻塞和唤醒线程的操作。它具有公平访问和非公平访问两种方式。
对于公平访问队列,被阻塞的线程可以按照阻塞的先后顺序访问队列,即先阻塞的线程先访问队列。而非公平队列,则是当队列可用时,阻塞的线程将进入争夺访问资源的竞争中,谁先抢到谁就执行,没有固定的先后顺序。
ArrayBlockingQueue的构造方法中,可以通过传入boolean类型的fair参数来选择是创建公平阻塞队列还是非公平阻塞队列。
LinkedBlockingQueue是一个由链表实现的有界阻塞队列。它的默认大小为Integer.MAX_VALUE,因此建议在使用LinkedBlockingQueue时手动传入所需的大小,避免队列过大导致机器负载过高或内存溢出等问题。
以下是ArrayBlockingQueue和LinkedBlockingQueue的基本概要:
- ArrayBlockingQueue:
- 类型:由数组实现的有界阻塞队列。
- 特点:具有公平访问和非公平访问两种方式。
- 构造函数:可以指定初始容量和是否使用公平访问。
- 方法:put()、take()、offer()、poll()等常用方法。
- LinkedBlockingQueue:
- 类型:由链表实现的有界阻塞队列。
- 特点:默认大小为Integer.MAX_VALUE,建议手动传入所需大小。
- 构造函数:可以指定初始容量或从其他集合中添加元素。
- 方法:put()、take()、offer()、poll()等常用方法。
ArrayBlockingQueue 实现队列达到一定数据量返回和达到一定时间返回
`ArrayBlockingQueue` 实现了 `BlockingQueue` 接口,提供了多个阻塞方法,包括 `put()`、`take()`、`offer()` 等。如果你想在队列达到一定数据量或达到一定时间时返回,可以结合这些阻塞方法进行实现。
一种实现方式是使用 `offer()` 方法,该方法会尝试将元素插入队列中,如果队列已经满了,它会返回 false,否则返回 true。结合计数器可以实现在队列达到一定数据量时返回。示例代码如下:
```java
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
int count = 0;
while (true) {
String data = getData();
if (queue.offer(data)) {
count++;
}
if (count >= 100) {
break;
}
}
```
另一种实现方式是使用 `poll()` 方法,该方法会尝试从队列中取出一个元素,如果队列为空,它会返回 null。结合时间戳可以实现在队列达到一定时间时返回。示例代码如下:
```java
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
long startTime = System.currentTimeMillis();
while (true) {
String data = getData();
if (queue.offer(data)) {
if (System.currentTimeMillis() - startTime >= 5000) {
break;
}
}
}
```
上述代码中,当队列中元素数量达到 100 个时,循环会退出;当从开始插入元素到现在的时间大于等于 5000 毫秒时,循环也会退出。你也可以使用 `put()` 和 `take()` 方法来实现类似的功能,这些方法会在队列满或空时阻塞线程,直到有空间或元素可用。