一、定义
阻塞队列,顾名思义,首先,他是一个队列,而一个阻塞队列在数据结构中所起到的作用如下:
线程1向阻塞队列中添加元素,线程2向阻塞队列中移除元素
*当阻塞队列是空时,从队列中获取元素的操作将会被阻塞。
*当阻塞队列是满时,从队列中添加元素的操作将会被阻塞。
二、为什么用阻塞队列,有什么好处?
在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤醒。
那为什么需要用阻塞队列呢?
好处是我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue给你包办了。
三、阻塞队列种类
1,ArrayBlockingQueue:由数组组成的有界阻塞队列
2,LinkedBlockingQueue:由链表组成的有界阻塞队列(但大小默认为Integer.MAX_VALUE,可认为是无界的)
3,priorityBlockingQueue:支持优先级排序的无界阻塞队列
4,DelayQueue:使用优先级队列实现的延迟无界队列
5,SynchronousQueue:不存储元素的阻塞队列,即单个元素的队列
6,LinkedTransferQueue:由链表结构组成的无界队列
7,LinkedBlockingDelay:由链表结构组成的双向阻塞队列
四、BlockingQueue核心方法
方法类型 | 抛出异常 | 特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll() | take() | poll(time,unit) |
检查 | element() | peek() | 不可用 | 不可用 |
1,抛出异常:当阻塞队列满时,再往队列里add插入元素会抛出illegalStateException:Queue full;当阻塞队列为空时,再从队列里remove移除元素会抛出NoSuchElementException
2,特殊值:插入方法,成功true,失败false;移除方法,成功返回出队列的元素,队列没有元素就返回null
3,阻塞:当阻塞队列满时,生产者线程继续往队列里put元素,队列会一直阻塞生产线程直到put数据或者响应中断退出;当阻塞队列空时,消费者线程试图从队列里take元素,队列会一直阻塞消费者线程直到队列可用
4,超时:当阻塞队列满时,队列会阻塞生产者线程一定时间,超时后生产者线程会退出。其实特殊值和超时是同一种类型。
五、SynchronousQueue的使用
SynchronousQueue没有容量,每一个put操作必须要等待一个take操作,否则不能继续添加元素,反之亦然。
package com.sy.blockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
public class SynchronousDemo {
public static void main(String[] args) {
BlockingQueue blockingQueue = new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"\t put 1");
blockingQueue.put(1);
System.out.println(Thread.currentThread().getName()+"\t put 2");
blockingQueue.put(2);
System.out.println(Thread.currentThread().getName()+"\t put 3");
blockingQueue.put(3);
} catch (Exception e) {
e.printStackTrace();
}
},"A").start();
new Thread(()->{
try {
//sleep是为了让线程暂停一会儿,能看到明显效果
//TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+"\t take "+blockingQueue.take());
//TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+"\t take "+blockingQueue.take());
//TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+"\t take "+blockingQueue.take());
} catch (Exception e) {
e.printStackTrace();
}
},"B").start();
}
}
运行结果:
A put 1
B take 1
A put 2
B take 2
A put 3
B take 3
