阻塞队列BlockingQueue的概念
队列:排队 特性:先进先出 FIFO
阻塞:必须要阻塞、不得不阻塞
阻塞队列的应用场景:多线程并发处理,线程池
BlockingQueue与List的千丝万缕
List的实现类和BlockingQueue的实现类
- List的实现类
- ArrayList
- LinkedList
- BlockingQueue的实现类
- ArrayBlockingQueue:数组实现的阻塞队列
- LinkedBlockingQueue:链表实现的阻塞队列
- SynchronousQueue:同步队列
ArrayBlockingQueue的四组API
ArrayBlockingQueue是BlockingQueue的实现类
1、ArrayBlockingQueue 是一个有限的blocking queue,由数组支持。
2、这个队列排列元素FIFO(先进先出)。
3、队列的固定大小创建后,容量无法更改。
四组API是以插入元素,移除元素和检查队首元素的基础上建立的,分别是:
抛出异常、返回特殊值、超时退出、一直等待
方法 | 抛出异常 | 返回特殊值 | 超时退出 | 一直等待 |
---|---|---|---|---|
插入 | add | offer | offer(e, timeout, unit) | put () |
移除 | remove | poll | poll(timeout, unit) | take() |
检查队首 | element | peek |
1、抛出异常
public class ArrayBlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
//创建大小为3的阻塞队列
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3);
//取不到值或者队列已满无法添加抛出异常
//queueApiException(arrayBlockingQueue);
//取不到值返回null或者队列已满无法添加返回false值
//queueApiNotException(arrayBlockingQueue);
//取不到值或者队列已满无法添加,若到超出指定时间则退出
//queueApiTimeOutExit(arrayBlockingQueue);
//取不到值或者队列已满无法添加一直阻塞等待下去直到能获取到值或者能添加值
//queueApiWaitingAlone(arrayBlockingQueue);
}
public static void queueApiException(ArrayBlockingQueue arrayBlockingQueue){
arrayBlockingQueue.add("a");
arrayBlockingQueue.add("b");
arrayBlockingQueue.add("c");
//arrayBlockingQueue.add("d"); //java.lang.IllegalStateException: Queue full
System.out.println(arrayBlockingQueue.remove());
System.out.println(arrayBlockingQueue.remove());
System.out.println(arrayBlockingQueue.remove());
//取出元素,队列为空抛出异常java.util.NoSuchElementException
//System.out.println(arrayBlockingQueue.remove());
//检查队首元素peek方法,没有元素抛出异常java.util.NoSuchElementException
//arrayBlockingQueue.element();
}
}
2、返回特殊值
public static void queueApiNotException(ArrayBlockingQueue arrayBlockingQueue){
System.out.println(arrayBlockingQueue.offer("a"));
System.out.println(arrayBlockingQueue.offer("b"));
System.out.println(arrayBlockingQueue.offer("c"));
//队列已满无法添加返回false值
//System.out.println(arrayBlockingQueue.offer("d")); //false 我们通常不希望代码报错!这时候就使用offer
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
//队列为空无法获取返回null
// System.out.println(arrayBlockingQueue.poll());
//System.out.println(arrayBlockingQueue.peek()); //null
}
3、超时等待
/**
* @description:设置等待时间,超时就退出
* @author yangxj
* @date 2020/2/23 17:54
*/
public static void queueApiTimeOutExit(ArrayBlockingQueue arrayBlockingQueue) throws InterruptedException {
System.out.println(arrayBlockingQueue.offer("a"));
System.out.println(arrayBlockingQueue.offer("b"));
System.out.println(arrayBlockingQueue.offer("c"));
// 超过3秒就不等待了,返回false
//System.out.println(arrayBlockingQueue.offer("d",3, TimeUnit.SECONDS));
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
// 超过3秒就不等待了,返回false
//System.out.println(arrayBlockingQueue.poll(3,TimeUnit.SECONDS));//返回null
}
4、一直等待
/**
* @description:一直等待阻塞
* @author yangxj
* @date 2020/2/23 17:54
*/
public static void queueApiWaitingAlone(ArrayBlockingQueue arrayBlockingQueue) {
try {
arrayBlockingQueue.put("a");
arrayBlockingQueue.put("b");
arrayBlockingQueue.put("c");
//一直等待
//arrayBlockingQueue.put("d");
System.out.println(arrayBlockingQueue.take());
System.out.println(arrayBlockingQueue.take());
System.out.println(arrayBlockingQueue.take());
//一直等待
//System.out.println(arrayBlockingQueue.take());//阻塞等待拿出元素
} catch (InterruptedException e) {
e.printStackTrace();
}
}
SynchronousQueue同步队列
SynchronousQueue是BlockingQueue的实现类,那它和ArrayBlockingQueue有什么区别呢?
SynchronousQueue是不能存储元素的,存入一个必须取出一个,否则无法添加元素,我们可以将其理解为数据块大小为1的ArrayBlockingQueue当中一种阻塞的put和take
/**
* 同步队列SynchronousQueue
* 1、不存储元素,队列是空的
* 2、每一个 put 操作。必须等待一个take。否则无法继续添加元素!
* 3、可以将SynchronousQueue理解为只有一个数据大小的ArrayBlockingQueue当中的一直阻塞put和take。
*/
public class SynchronousQueueDemo {
public static void main(String[] args) {
SynchronousQueue synchronousQueue = new SynchronousQueue();
//添加元素线程
new Thread(() -> {
try {
synchronousQueue.put("1");
System.out.println(Thread.currentThread().getName() + ":put 1");
synchronousQueue.put("2");
System.out.println(Thread.currentThread().getName() + ":put 2");
synchronousQueue.put("3");
System.out.println(Thread.currentThread().getName() + ":put 3");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"put element").start();
//读取元素线程
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+synchronousQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"get element").start();
}
}