阻塞队列(BlockingQueue)是一个支持阻塞操作的队列。在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列能存储元素。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
阻塞队列提供了四种处理方法(Queue接口中没有一直阻塞和超时退出对应的方法):
方法\不能成功的处理方式 | 抛出异常 | 返回特殊值 | 一直阻塞 | 阻塞至超时退出 |
---|---|---|---|---|
插入方法 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除方法 | remove() | poll() | take() | poll(time,unit) |
检查方法 | element() | peek() |
异常:是指当阻塞队列满时候,再往队列里插入元素,会抛出IllegalStateException("Queue full")异常。当队列为空时,从队列里获取元素时会抛出NoSuchElementException异常 。
- 返回特殊值:插入方法会返回是否成功,成功则返回true。移除方法,则是从队列里拿出一个元素,如果没有则返回null。
- 一直阻塞:当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到拿到数据,或者响应中断退出。当队列空时,消费者线程试图从队列里take元素,队列也会阻塞消费者线程,直到队列可用。
- 超时退出:当阻塞队列满时,队列会阻塞生产者线程一段时间,如果超过一定的时间,生产者线程就会退出。
更多内容,参考:https://www.cnblogs.com/bjxq-cs88/p/9759571.html
消费者:
public class Consumer implements Runnable {
private BlockingQueue<String> messageQueue;
public Consumer(BlockingQueue<String> messageQueue) {
this.messageQueue = messageQueue;
}
@Override
public void run() {
int i = 0;
while (true) {
if(messageQueue.size() == 0){
System.out.println("消费者队列空了,先等待");
}
i++;
try {
messageQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者消息" + i);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
生产者:
public class Producer implements Runnable {
private BlockingQueue<String> messageQueue;
public Producer(BlockingQueue<String> messageQueue) {
this.messageQueue = messageQueue;
}
@Override
public void run() {
int i = 0;
while (true) {
if (messageQueue.remainingCapacity() == 0) {
System.out.println("生产者队列满了,先等待");
}
i++;
String message = "消息" + i;
System.out.println("生产者生产消息:" + message);
try {
messageQueue.put(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试:
public class Test {
public static void main(String[] args) {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
Thread producerThread = new Thread(producer);
Thread consumerThread = new Thread(consumer);
producerThread.start();
consumerThread.start();
}
}
结果:
消费者队列空了,先等待
生产者生产消息:消息1
消费者消息1
生产者生产消息:消息2
生产者生产消息:消息3
生产者生产消息:消息4
消费者消息2
生产者生产消息:消息5
生产者生产消息:消息6
消费者消息3
生产者生产消息:消息7
生产者生产消息:消息8
生产者队列满了,先等待
生产者生产消息:消息9
消费者消息4
生产者队列满了,先等待
生产者生产消息:消息10
消费者消息5
生产者队列满了,先等待
生产者生产消息:消息11
...