详解Java阻塞队列(BlockingQueue)的四组API
什么是阻塞队列?
队列是我们常见的一种数据结构,特性就是FIFO(先进先出)。而阻塞队列,前面加了阻塞两个字,顾名思义就是对队列为空的时候,“取”操作会使队列block,“添加/存入”操作也会使队列block。 BlockingQueue是一个接口,我们所知道的实现类就有七个
这里我们并不打算介绍这些实现类的特性,而是要介绍他们的四组共同API。
四组API
这里我们先用表格简单了解一下,下面再用实例代码来介绍。
方式 | 抛出异常 | 有返回值,不抛出异常 | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll() | take() | poll(time,unit) |
检测队首元素 | element() | peek() | 无 | 无 |
第一组 |
||||
1、添加抛出异常 |
public class Demo01 {
public static void main(String[] args) {
// 构造方法参数:public ArrayBlockingQueue(int capacity, boolean fair)
// 第一个参数:初始化阻塞队列的容量大小
// 第二个参数:指定该阻塞队列是否为公平或不公平锁
BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);
// 添加元素
queue.add("a");
queue.add("b");
queue.add("c");
}
}
运行结果:
2、移除抛出异常
public class Demo01 {
public static void main(String[] args) {
// 构造方法参数:public ArrayBlockingQueue(int capacity, boolean fair)
// 第一个参数:初始化阻塞队列的容量大小
// 第二个参数:指定该阻塞队列是否为公平或不公平锁
BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);
// 添加元素
System.out.println(queue.add("a"));
System.out.println(queue.add("b"));
// 移除元素
queue.remove();
queue.remove();
queue.remove();
}
}
运行结果:
第二组
1、添加有返回值
package com.lzp.blockqueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* @Author LZP
* @Date 2020/8/8 8:12
* @Version 1.0
*
* 有返回值,且不抛出异常
*/
public class Demo02 {
public static void main(String[] args) {
// 创建阻塞队列对象
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
// 添加元素:若添加成功,则返回true,反之,则返回false
System.out.println(queue.offer(1));
System.out.println(queue.offer(2));
System.out.println(queue.offer(3));
System.out.println(queue.offer(4));
}
}
运行结果:
2、移除有返回值
package com.lzp.blockqueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* @Author LZP
* @Date 2020/8/8 8:12
* @Version 1.0
*
* 有返回值,且不抛出异常
*/
public class Demo02 {
public static void main(String[] args) {
// 创建阻塞队列对象
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
// 添加元素:若添加成功,则返回true,反之,则返回false
System.out.println(queue.offer(1));
System.out.println(queue.offer(2));
System.out.println(queue.offer(3));
System.out.println(queue.offer(4));
// 移除元素:若移除成功,则返回移除的值,反之,则返回false
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
}
}
运行结果:
第三组
1、添加时,如果队列已满,则阻塞等待
package com.lzp.blockqueue;
import java.util.Iterator;
import java.util.concurrent.*;
/**
* @Author LZP
* @Date 2020/8/8 8:28
* @Version 1.0
*
* 阻塞等待,即一直等待,直到可以往队列里添加或移除元素为止
*
* 注意:普通队列只能从队首取第一个元素
* 添加阻塞
*/
public class Demo03 {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(4);
// 开启一个线程先把队列里添满元素
new Thread(() -> {
System.out.println("-----" + Thread.currentThread().getName() + "正在往阻塞队列里添加元素------");
try {
for (int i = 1; i <= 4; i++) {
TimeUnit.SECONDS.sleep(1);
queue.put(i + "");
// element()方法,用来取队列的队首元素
System.out.println("-----成功添加第" + i + "个元素-----" + i);
}
System.out.println("-----" + Thread.currentThread().getName() + "添加元素完毕------");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// 判断当前线程数,如果>2则一直等待,不能往下执行
// 为了保证能将队列添满元素,再进行后续操作
while ((Thread.activeCount() > 2)) {
}
// System.out.println("遍历开始");
// Iterator<String> iterator = queue.iterator();
// while (iterator.hasNext()) {
// System.out.println(iterator.next());
// }
// System.out.println("遍历结束");
// 此时开启一个线程去往队列里添加元素
new Thread(() -> {
try {
System.out.println("-----" + Thread.currentThread().getName() + "开始添加元素------");
String str = "李时珍的皮";
queue.put(str);
System.out.println("-----" + Thread.currentThread().getName() + "成功添加元素------" + str);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(3);
// // 移除元素
// System.out.println(queue.take());
// 让主线程等了3秒之后,然后派一个线程去移除元素
new Thread(() -> {
try {
System.out.println("-----" + Thread.currentThread().getName() + "开始移除元素------");
String str = queue.take();
System.out.println(str);
System.out.println("-----" + Thread.currentThread().getName() + "成功移除元素------" + str);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
运行结果:
2、移除元素时,如果队列已空,则阻塞等待
package com.lzp.blockqueue;
import java.util.Iterator;
import java.util.concurrent.*;
/**
* @Author LZP
* @Date 2020/8/8 8:28
* @Version 1.0
*
* 阻塞等待,即一直等待,直到可以往队列里添加或移除元素为止
*
* 注意:普通队列只能从队首取第一个元素
* 移除阻塞
*/
public class Demo03 {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);
System.out.println("刚开始,队列里的元素:" + queue);
// 开启一个线程去移除元素
new Thread(() -> {
try {
System.out.println("开始移除时,队列里的元素:" + queue);
System.out.println("正在移除元素:" + queue.take());
System.out.println("移除完后,队列里的元素:" + queue);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(3);
// 等待3秒后,再开启一个线程去添加元素
new Thread(() -> {
try {
// 添加元素
queue.put("Hello");
queue.put("World");
System.out.println("添加完后,队列里的元素:" + queue);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
运行结果:
第四组
1、添加时,如果队列已满,则超时等待(即等待设置的时间过后就立马返回,不会一直阻塞下去)
package com.lzp.blockqueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* @Author LZP
* @Date 2021/2/28 10:24
* @Version 1.0
* <p>
* 超时等待
*/
public class Demo04 {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
// 先将队列填满
for (int i = 1; i <= 3; i++) {
String e = i + "";
System.out.println("添加元素:" + e + "返回值为:" + queue.offer(e, 2, TimeUnit.SECONDS));
}
System.out.println("等2秒后");
// 此时队列已满,再向队列中添加元素时,就会出现超时等待的情况
System.out.println("返回值为:" + queue.offer(4 + "", 2, TimeUnit.SECONDS));
}
}
运行结果:
2、移除时,如果队列已空,则超时等待(即等待设置的时间过后就立马返回,不会一直阻塞下去)
package com.lzp.blockqueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* @Author LZP
* @Date 2021/2/28 10:24
* @Version 1.0
* 超时等待
* 移除元素
*/
public class Demo04 {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
System.out.println("等2秒后");
// 此时队列为空,移除时会发生超时阻塞,且返回null
System.out.println("返回值为:" + queue.poll(2, TimeUnit.SECONDS));
}
}
运行结果: