一、概述
1. BlockqingQueue是阻塞式队列中的顶级接口
2. 不同于以往的队列,BlockingQueue一般是有界限的
3. 在队列为空的时候进行获取操作会产生阻塞
4. 在队列已满的情况下继续存储元素会产生阻塞
5. 遵循先进先出(FIFO)的原则
6. 适用于生产消费模型
二、重要方法
抛出异常 返回特殊值 阻塞 定时阻塞
队列已满时,添加 add(o) offer(o) put(o) offer(o, time, unit)
队列为空时,获取 remove() poll() take() poll(time, unit)
三、ArrayBlockingQueue - 阻塞式顺序队列
1. 在使用的时候需要指定容量/界限
2. 底层基于数组来存储数据
3. 容量在指定之后不能改动
4. 遵循先进先出(FIFO)的原则
四、LinkedBlockingQueue - 阻塞式链式队列
1. 在使用的时候可以指定容量也可以不指定容量
2. 如果不指定容量,则容量默认为Integer.MAX_VALUE,此时认为容量是无限的
3. 如果指定容量,则容量指定之后不可变
4. 底层基于节点(链表)来存储数据
5. 遵循先进先出(FIFO)的原则
五、PriorityBlockingQueue - 阻塞式优先级队列
概述
1. 在使用的时候可以指定容量也可以不指定
2. 如果不指定容量,则容量默认为11
3. 如果指定容量,则容量指定之后不可改变
4. 在指定容量的时候,最大不能超过Integer.MAX_VALUE-8
5. PriorityBlockingQueue要求存储的元素对应的类必须实现Comparable接口,重写其中的compareTo方法来指定比较规则
6. PriorityBlockingQueue在存储元素的时候会根据指定的比较规则对元素进行排序
7. PriorityBlockingQueue在迭代的时候不保证元素的排序顺序
示例
public class PriorityBlockingQueueDemo {
public static void main(String[] args) throws Exception {
// 创建队列
PriorityBlockingQueue<Student> queue = new PriorityBlockingQueue<>();
// 添加元素
queue.put(new Student("Amy", 16));
queue.put(new Student("Bob", 25));
queue.put(new Student("Cathy", 20));
queue.put(new Student("David", 13));
// 遍历队列
// 需要注意的是,如果想要拿到排序的结果,不能以迭代的方法获取
for (int i = 0; i < 4; i++) {
System.out.println(queue.take());
}
}
}
class Student implements Comparable<Student> {
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
// 在这个方法中指定比较规则
// 根据学生的年龄进行升序排序
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
六、SynchronousQueue - 同步队列
1. 容量默认为1,并且只能为1,因此只能存储1个元素
2. 如果该队列已有一个元素,则试图向队列中新添一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走
3. 如果该队列为空,则试图从队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中添加了一个新的元素
4. 一般会将同步队列称之为是数据的汇合点
七、BlockingDeque - 阻塞式双向队列
1. BlockingDeque继承了BlockingQueue
2. 在使用的时候,也是需要指定容量的
3. 该队列称之为双向队列,即队列的两端都可以添加元素,也可以从队列的两端获取元素
八、BlockingQueue中实现入队和出队的操作
- 使用object中的wait和notify来实现阻塞队列
public class Test {
//模拟生产和消费的对象
static class Buffer {
private int maxSize;
private List<Date> storage;
Buffer(int size) {
maxSize = size;
storage = new LinkedList<>();
}
//生产方法
public synchronized void put() {
try {
while (storage.size() == maxSize) {//如果队列满了
System.out.print(Thread.currentThread().getName() + ": wait \n");
wait();//阻塞线程
}
storage.add(new Date());
System.out.print(Thread.currentThread().getName() + ": put:" + storage.size() + "\n");
Thread.sleep(1000);
notifyAll();//唤起线程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//消费方法
public synchronized void take() {
try {
while (storage.size() == 0) {//如果队列空了
System.out.print(Thread.currentThread().getName() + ": wait \n");
wait();//阻塞线程
}
Date d = ((LinkedList<Date>) storage).poll();
System.out.print(Thread.currentThread().getName() + ": take:" + storage.size() + "\n");
Thread.sleep(1000);
notifyAll();//唤起线程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//生产者
static class Producer implements Runnable {
private Buffer buffer;
Producer(Buffer b) {
buffer = b;
}
@Override
public void run() {
while (true) {
buffer.put();
}
}
}
//消费者
static class Consumer implements Runnable {
private Buffer buffer;
Consumer(Buffer b) {
buffer = b;
}
@Override
public void run() {
while (true) {
buffer.take();
}
}
}
//
public static void main(String[] arg) throws InterruptedException {
Buffer buffer = new Buffer(5);
Producer producer = new Producer(buffer);
Consumer consumer = new Consumer(buffer);
//创建线程执行生产和消费
for (int i = 0; i < 3; i++) {
new Thread(producer, "producer-" + i).start();
}
//可以清楚地看到队满阻塞
Thread.sleep(10000L);
for (int i = 0; i < 3; i++) {
new Thread(consumer, "consumer-" + i).start();
}
}
}
- BlockingQueue中的Lock与Condition实现阻塞队列的入队与出队
public class Test2 {
static class Buffer {
private final Lock lock;
private final Condition notFull;
private final Condition notEmpty;
private int maxSize;
private List<Date> storage;
Buffer(int size) {
//使用锁lock,并且创建两个condition,相当于两个阻塞队列
lock = new ReentrantLock();
notFull = lock.newCondition();
notEmpty = lock.newCondition();
maxSize = size;
storage = new LinkedList<>();
}
public void put() {
lock.lock();
try {
while (storage.size() == maxSize) {//如果队列满了
System.out.print(Thread.currentThread().getName() + ": wait \n");
notFull.await();//阻塞生产线程
}
storage.add(new Date());
System.out.print(Thread.currentThread().getName() + ": put:" + storage.size() + "\n");
Thread.sleep(1000);
notEmpty.signalAll();//唤醒消费线程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void take() {
lock.lock();
try {
while (storage.size() == 0) {//如果队列满了
System.out.print(Thread.currentThread().getName() + ": wait \n");
notEmpty.await();//阻塞消费线程
}
Date d = ((LinkedList<Date>) storage).poll();
System.out.print(Thread.currentThread().getName() + ": take:" + storage.size() + "\n");
Thread.sleep(1000);
notFull.signalAll();//唤醒生产线程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
static class Producer implements Runnable {
private Buffer buffer;
Producer(Buffer b) {
buffer = b;
}
@Override
public void run() {
while (true) {
buffer.put();
}
}
}
static class Consumer implements Runnable {
private Buffer buffer;
Consumer(Buffer b) {
buffer = b;
}
@Override
public void run() {
while (true) {
buffer.take();
}
}
}
public static void main(String[] arg) {
Buffer buffer = new Buffer(10);
Producer producer = new Producer(buffer);
Consumer consumer = new Consumer(buffer);
for (int i = 0; i < 3; i++) {
new Thread(producer, "producer-" + i).start();
}
for (int i = 0; i < 3; i++) {
new Thread(consumer, "consumer-" + i).start();
}
}
}