1.简介
阻塞队列 BlockingQueue:阻塞即线程想要获取资源却没有资源的现象,队列即先进先出数据结构 ,是生产者存放元素的容器,而消费者也只从容器里拿元素。
- 当阻塞队列为空时,从队列中获取元素的Thread1操作将会被阻塞
- 当阻塞队列为满时,从队列中添加元素的Thread2操作将会被阻塞
2.场景
餐饮店餐位被占满后,此时如果还有客人到来,餐饮店应该让后来的这些客人去等待区等待,不能粗暴通知他们无座,然后抛弃他们。
- 此时可使用的餐位数就相当于阻塞队列内部的可获取元素个数,当餐位无空余时,想要获取餐位的客人,将会被阻塞。
- 有客人就餐完毕,就相当于往阻塞队列中添加元素,但因为总餐位的限制,当阻塞队列中的餐位达到餐饮店总餐位时,也不会再插入可获取的餐位
3.阻塞队列的好处
我们不再需要关心什么时候需要去阻塞线程,什么时候需要去唤醒线程,全部交给BlockingQueue来判断。
- 只要BlockingQueue中的元素为空,则消费者线程被阻塞,当生产者线程执行时,该生产者线程唤醒所有消费者线程。
- 只要BlockingQueue中的元素为满,则生产者线程被阻塞,当消费者线程执行时,该消费者线程唤醒所有生产者线程。
3-1.阻塞队列的组织架构
3-2.线程池的底层为下图中标红的三个结构
3-3.各种阻塞队列中共有的核心方法如下图(其他方法很少使用到)
将加入、移除、检查按照错误处理的方式分成四组api调用:
-
抛出异常组:是指当阻塞队列满时候,再往队列里插入元素,会抛出 IllegalStateException(“Queue full”) 异常。当队列为空时,从队列里获取元素时会抛出 NoSuchElementException 异常 。
-
返回特殊值组:插入方法会返回是否成功,成功则返回 true。移除方法,则是从队列里拿出一个元素,如果没有则返回 null
-
一直阻塞组:当阻塞队列满时,如果生产者线程往队列里 put 元素,队列会一直阻塞生产者线程,直到拿到数据,或者响应中断退出。当队列空时,消费者线程试图从队列里 take 元素,队列也会阻塞消费者线程,直到队列可用。(消息中间件使用较多,因为消息不能因为阻塞而丢失)- 谚语:死战不退
-
超时退出组:当阻塞队列满时,队列会阻塞生产者线程一段时间,如果超过一定的时间,生产者线程就会退出,并且返回插入结果,成功返回true。api参数中e为插入元素,time为时间数,unit为time的单位(TimeUnit.SECONDS)。- 谚语:过时不候
4.核心方法代码演示(抛出异常组-相对暴力)
4-1.add添加元素方法(无异常添加元素代码 和 有异常添加元素代码)
无异常添加演示:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
// 创建一个只有3个位置可用的阻塞队列
// 上下对比:List list = new ArrayList(3)
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
// 输出添加结果boolean值
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
}
}
4-1-2.有异常添加演示:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
// 创建一个只有3个位置可用的阻塞队列
// 上下对比:List list = new ArrayList(3)
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
// 输出添加结果boolean值
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
System.out.println(blockingQueue.add("d"));
}
}
抛出了队列满溢异常:
4-2.remove移除队头元素方法(无异常移除元素代码 和 有异常移除元素代码)
4-2-1.无异常移除队头元素元素演示:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
// 创建一个只有3个位置可用的阻塞队列
// 上下对比:List list = new ArrayList(3)
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
// 输出添加boolean值
System.out.println("开始添加");
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
// 输出移除元素boolean值
System.out.println("开始移除");
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
}
}
4-2-1.有异常移除队头元素元素演示:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
// 创建一个只有3个位置可用的阻塞队列
// 上下对比:List list = new ArrayList(3)
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
// 输出添加boolean值
System.out.println("开始添加");
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
// 输出移除元素boolean值
System.out.println("开始移除");
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
}
}
4-3.elemet获取队头元素(FIFO)方法
4-3-1.获取队头元素演示(可用于检查队是否有可用元素):
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
// 创建一个只有3个位置可用的阻塞队列
// 上下对比:List list = new ArrayList(3)
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
// 输出添加boolean值
System.out.println("开始添加");
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
System.out.println("对头元素: " + blockingQueue.element());
// 输出移除元素boolean值
System.out.println("开始移除");
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
}
}
5.核心方法代码演示(返回boolean组-相对温和)
5-1.offer添加元素方法(正确添加元素代码 和 错误添加元素代码)
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
// 创建一个只有3个位置可用的阻塞队列
// 上下对比:List list = new ArrayList(3)
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
// 输出添加boolean值
System.out.println("开始添加");
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
System.out.println(blockingQueue.offer("c"));
}
}
5-2.poll移除元素方法(正确移除元素代码 和 错误移除元素代码)
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
// 创建一个只有3个位置可用的阻塞队列
// 上下对比:List list = new ArrayList(3)
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
// 输出添加boolean值
System.out.println("开始添加");
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
// 输出移除元素boolean值
System.out.println("开始移除");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
}
}