介绍
LinkedBlockingDeque 是一个基于 链表 的 双端阻塞队列,线程安全,不允许插入 null 值
与 LinkedBlockingQueue 类似,但两端都可以放数据、取数据
应用场景
一般多用于 生产者消费者模式,详见 链接
构造方法
创建一个容量为
Integer.MAX_VALUE的队列:LinkedBlockingDeque()创建一个固定容量的 队列:
LinkedBlockingDeque(int capacity)创建一个容量为
Integer.MAX_VALUE的队列,包含 collection 的元素LinkedBlockingDeque(Collection<? extends E> c)
方法总结
| 方法 | 抛出异常 | 正常运行 | 阻塞 | 阻塞特定时间 |
|---|---|---|---|---|
| 尾部添加元素 | add(e)、addLast(e) | offer(e)、offerLast(e) | put(e)、putLast(e) | offer(e, time, unit) |
| 头部添加元素 | addFirst(e) | offerFirst(e) | putFirst(e) | offerFirst(e, time, unit) |
| 头部取出元素 | remove()、removeFirst() | poll()、pollFirst() | take()、takeFirst() | poll(time, unit)、pollFirst(time, unit) |
| 尾部取出元素 | removeLast() | pollLast() | takeLast() | pollLast(time, unit) |
添加元素
put() 方法
如果队列已满,线程阻塞
例子:
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
try {
queue.put(1);
System.out.println("添加第一个元素,队列元素数量:"+queue.size());
queue.put(2);
System.out.println("添加第二个元素,队列元素数量:"+queue.size());
queue.put(3);
System.out.println("添加第三个元素,队列元素数量:"+queue.size());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
执行结果:
添加第一个元素,队列元素数量:1
添加第二个元素,队列元素数量:2
说明添加第二个元素后,队列已满,线程阻塞,一直等到能够添加该元素
add() 方法
如果队列已满,报下面错误:
java.lang.IllegalStateException: Queue full
例子:
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
queue.add(1);
System.out.println("添加第一个元素,队列元素数量:"+queue.size());
queue.add(2);
System.out.println("添加第二个元素,队列元素数量:"+queue.size());
queue.add(3);
System.out.println("添加第三个元素,队列元素数量:"+queue.size());
}
执行结果:
添加第一个元素,队列元素数量:1
添加第二个元素,队列元素数量:2
Exception in thread "main" java.lang.IllegalStateException: Queue full
at java.util.AbstractQueue.add(AbstractQueue.java:98)
at LinkedBlockingQueueTest.main(LinkedBlockingQueueTest.java:11)
说明添加第二个元素后,队列已满,就抛错
offer() 方法
如果队列已满,程序正常运行,但是不再新增元素
例子:
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
queue.offer(1);
System.out.println("添加第一个元素,队列元素:"+queue.size());
queue.offer(2);
System.out.println("添加第二个元素,队列元素:"+queue.size());
queue.offer(3);
System.out.println("添加第三个元素,队列元素:"+queue.size());
}
执行结果:
添加第一个元素,队列元素:1
添加第二个元素,队列元素:2
添加第三个元素,队列元素:2
取元素
take() 方法
返回并移除第一个元素,当队列为空,线程阻塞
例子-队列为空时:
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
try {
queue.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
执行结果:程序没有执行结束
说明队列没有元素时,一直等待,即:阻塞
例子-队列有元素时
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
queue.add(100);
queue.add(200);
System.out.println("队列元素数量:"+queue.size());
try {
Object o = queue.take();
System.out.println("取出第一个元素:"+o);
System.out.println("队列元素数量:"+queue.size());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
执行结果:
队列元素数量:2
取出第一个元素:100
队列元素数量:1
说明队列有数据时,返回第一个元素,并移除
poll() 方法
返回并移除第一个元素,队列为空时返回 null
例子-队列为空时:
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
Object o = queue.poll();
System.out.println("取出第一个元素:"+o);
}
执行结果:
取出第一个元素:null
说明队列没有数据时,返回 null
例子-队列有元素时:
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
queue.add(100);
queue.add(200);
System.out.println("队列元素数量:"+queue.size());
Object o = queue.poll();
System.out.println("取出第一个元素:"+o);
System.out.println("队列元素数量:"+queue.size());
}
执行结果:
队列元素数量:2
取出第一个元素:100
队列元素数量:1
说明队列有数据时,返回第一个元素,并移除
remove() 方法
返回并移除第一个元素,队列为空时抛异常:java.util.NoSuchElementException
例子-队列为空时:
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
Object o = queue.remove();
System.out.println("取出第一个元素:"+o);
}
执行结果:
Exception in thread "main" java.util.NoSuchElementException
说明队列没有数据时,会抛错
例子-有元素时:
public static void main(String[] args) {
LinkedBlockingQueue queue = new LinkedBlockingQueue(2);
queue.add(100);
queue.add(200);
System.out.println("队列元素数量:"+queue.size());
Object o = queue.remove();
System.out.println("取出第一个元素:"+o);
System.out.println("队列元素数量:"+queue.size());
}
执行结果:
队列元素数量:2
取出第一个元素:100
队列元素数量:1
说明队列有数据时,返回第一个元素,并移除
其他方法
remainingCapacity():获取队列中剩余的空间
size():获得队列中有多少值
应用场景
应用在 生产者/消费者模式
生产者
package 生产者模式;
import java.util.concurrent.LinkedBlockingQueue;
public class Productor implements Runnable {
int index=1;
LinkedBlockingQueue queue =null;
public Productor(LinkedBlockingQueue queue){
this.queue =queue;
}
@Override
public void run() {
while (true) {
if (queue.size() == Main.QUEUE_MAX) {
System.out.println("队列的馒头数量为:"+ queue.size()+",达到上限,不在生产");
}
String str = "馒头-编号:" + index;
try {
queue.put(str);
System.out.println("生产一个 " + str);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
index++;
// 模拟生产馒头,生产馒头慢,暂停200毫秒
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者
package 生产者模式;
import java.util.concurrent.LinkedBlockingQueue;
public class Customer implements Runnable {
LinkedBlockingQueue queue =null;
public Customer(LinkedBlockingQueue queue){
this.queue =queue;
}
@Override
public void run() {
while (true) {
if (queue.size() == 0) {
System.out.println("队列的馒头数量为:0,暂停营业");
}
try {
System.out.println("卖出 " + queue.take());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 模拟卖馒头,卖馒头快,暂停20毫秒
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
主启动类
package 生产者模式;
import java.util.concurrent.LinkedBlockingQueue;
public class Main {
final static int QUEUE_MAX = 5;
public static void main(String[] args) {
LinkedBlockingQueue queue=new LinkedBlockingQueue(QUEUE_MAX);
Productor p=new Productor(queue);
Customer c=new Customer(queue);
Thread tp=new Thread(p);
Thread tc=new Thread(c);
tc.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
tp.start();
}
}
执行结果:
队列的馒头数量为:0,暂停营业
生产一个 馒头-编号:1 // 生成一个馒头
卖出 馒头-编号:1 // 卖出一个馒头
生产一个 馒头-编号:2 // 生成馒头快,连续生成5个馒头
生产一个 馒头-编号:3
生产一个 馒头-编号:4
生产一个 馒头-编号:5
生产一个 馒头-编号:6
队列的馒头数量为:5,达到上限,不在生产 // 队列已满,馒头放不进去,阻塞生产者线程
卖出 馒头-编号:2 // 消费者线程时间到,卖出一个馒头(该馒头是第二个馒头),此时队列空出一个位置
生产一个 馒头-编号:7 // 队列空出一个位置,可以放进去一个馒头,队列又满了
队列的馒头数量为:5,达到上限,不在生产 // 队列已满,馒头放不进去,阻塞生产者线程
卖出 馒头-编号:3
生产一个 馒头-编号:8
队列的馒头数量为:5,达到上限,不在生产
卖出 馒头-编号:4
生产一个 馒头-编号:9
参考:
https://juejin.cn/post/7000515796053000228
https://blog.csdn.net/baofengyu90/article/details/84564013
https://blog.csdn.net/qq_24614847/article/details/109443062