BlockingQueue 是由数组支持的有界阻塞队列。此队列对元素FIFO(先进先出)进行排序。队列的开头是已在队列中最长时间的元素。队列的尾部是最短时间出现在队列中的元素。新元素插入到队列的尾部,并且队列检索操作在队列的开头获取元素
此类支持可选的公平性策略,用于订购正在等待的生产者和使用者线程。默认情况下,不保证此排序。但是,将公平性设置为true构造的队列将按FIFO顺序授予线程访问权限。公平通常会降低吞吐量,但会减少可变性并避免饥饿
当队列为空时,从队列中获取元素的操作将会被阻塞(当试图从空的队列中获取元素的线程将会被阻塞,直到其它线程往空的队列插入新的元素)
当队列为满时,从队列中添加元素的操作将会被阻塞(当试图向已满的队列中添加新元素的线程将会被阻塞,直到其它线程从队列中移除 一个或者多个或者完全清空,使队列变得空闲起来并后续新增)
方法类型 | 抛出异常 | 特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll() | take() | poll(time,unit) |
检查 | element() | peek() | 不可用 | 不可用 |
抛出异常 | 当阻塞队列满时,再往队列里 add 插入元素会抛出 IllegalStateException(“Queue full”);当阻塞队列为空时,再从队列里 remove 移除元素会抛出 NoSuchElementException |
---|---|
特殊值 | 插入方法,成功返回 true,失败返回 false;移除方法,成功返回出队列的元素,队列里没有就返回 null |
一直阻塞 | 当阻塞队列满时,生产者线程继续往队列里 put 元素,队列会一直阻塞生产者线程直到 put 数据或者响应中断退出;当队列为空时,消费者线程视图从队列里 take 元素,队列会一直阻塞消费者直到队列可用 |
超时退出 | 当阻塞队列满时,队列会阻塞生产者线程一定时间,超过限时后生产者线程会退出 |
假如现在队列里有一个元素,第一个元素也叫头节点
然后我们添加一个元素,当我们添加一个元素时,那么这个新添加的元素就是尾节点了(头节点指向尾节点)
同样地,再添加一个元素也是一样
在上图中移除一个元素是移除最先添加的元素,也就是 11
从上图中再移除一个元素,也就是 12
那么这个抛出异常怎么理解呢?可以来一段代码测试一下
package juc;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* @author Woo_home
* @create by 2020/3/14
*/
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
// 创建一个 ArrayBlockingQueue 并初始化大小为 3
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
// 往队列里面添加 3 个元素,add 成功会返回 true
System.out.println(queue.add("a"));
System.out.println(queue.add("b"));
System.out.println(queue.add("c"));
}
}
输出:
因为我们已经将 ArrayBlockingQueue 初始化为 3,所以添加 3 个元素的时候是可以的,但是当我们在添加一个元素的时,就会抛出一个异常,如下:
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.add("a"));
System.out.println(queue.add("b"));
System.out.println(queue.add("c"));
// 再次添加一个元素
System.out.println(queue.add("x"));
}
}
抛出异常了,异常为 Queue full(队列已经满了)
而 ArrayBlockingQueue 的 add(E e) 方法的源码如下:
可以发现当我们使用 add() 方法的时候使用的是 ArrayBlockingQueue 的 add() 方法
而 ArrayBlockingQueue 的 add 方法实际调用的是父类 AbstractQueue 的 add() 方法,AbstractQueue 的 add() 方法在每次添加元素时都会使用 offer 方法(该方法是实现 Queue 接口的方法)进行判断,判断此时的队列是否已经满了,如果没满,则添加元素并且返回 true,否则抛出 IllegalStateException(“Queue full”) 异常
package juc;
/**
* @author Woo_home
* @create by 2020/3/14
*/
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
queue.add("a");
queue.add("b");
queue.add("c");
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
}
}
这个程序往队列里面添加添加三个元素,然后取出三个元素,上面已经讲过,队列是遵循先进先出原则,移除是移除最先添加的元素
输出:
这时的队列元素已经全部移除,已经为空了,当再次 remove 时则会抛出 NoSuchElementException 异常,如下:
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
queue.add("a");
queue.add("b");
queue.add("c");
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
// 经过上面的 remove,队列此时已为空
System.out.println(queue.remove());
}
}
输出:
当队列为空时,在往队列里 remove 移除元素会抛出 NoSuchElementException 异常
看下下面这段代码
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.offer("a"));
System.out.println(queue.offer("b"));
System.out.println(queue.offer("c"));
System.out.println(queue.offer("x"));
}
}
输出:
offer 的操作跟 add 差不多,都是添加元素,但是 offer 方法添加元素当添加元素的数量大于初始化的值时会返回一个 false 而不是抛出异常
poll() 操作跟 remove() 操作差不多,都是移除元素,但是 poll 的移除是成功返回队列的元素,队列里没有的元素就返回 null 而不是抛出异常
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.offer("a"));
System.out.println(queue.offer("b"));
System.out.println(queue.offer("c"));
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
}
}
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
queue.put("a");
queue.put("b");
queue.put("c");
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
}
}
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.offer("a"));
System.out.println(queue.offer("b"));
System.out.println(queue.offer("c"));
// 如果队列满了超过 3 s,则返回 false
System.out.println(queue.offer("a", 3L,TimeUnit.SECONDS));
}
}