队列关系图
参考 : http://tutorials.jenkov.com/java-concurrency/blocking-queues.html
基本操作
方法 | 含义 | 返回 |
---|---|---|
add | 增加一个元素 | 如果队列已满,则抛出一个IIIegaISlabEepeplian异常 |
remove | 移除并返回队列头部的元素 | 如果队列为空,则抛出一个 |
element | 返回队列头部的元素 | 如果队列为空,则抛出一个NoSuchElementException异常 |
offer | 添加一个元素并返回true | 如果队列已满,则返回false |
poll | 移除并返问队列头部的元素 | 如果队列为空,则返回null |
peek | 返回队列头部的元素 | 如果队列为空,则返回null |
put | 添加一个元素 | 如果队列满,则阻塞 |
take | 移除并返回队列头部的元素 | 如果队列为空,则阻塞 |
- 实现阻塞的操作主要是
put
和take
一个简单例子
package com.example.arrays;
import lombok.Data;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 模拟消息队列
*/
public class TestQueue {
/**
* 测试使用
*/
@Test
public void testA() throws InterruptedException {
//启动一个容量为2的ArrayBlockingQueue队列
BlockingQueue<Message> queue = new ArrayBlockingQueue<>(2);
//启动一个容量为2的LinkedBlockingQueue队列(和操作基本一致)
// BlockingQueue<Message> queue = new LinkedBlockingQueue<>(2);
Producer producer = new Producer(queue);
Consumer consumer1 = new Consumer(queue);
consumer1.setName("线程-1:");
consumer1.start();
Consumer consumer2 = new Consumer(queue);
consumer2.setName("线程-2:");
consumer2.start();
//先开启消费者线程,再让生产者产生消息,不然会进入死循环
for(int i=0;i<10;i++){
Message m = new Message("消息@"+i);
producer.sendMessage(m);
Thread.sleep(1000);
}
}
/**
* 一个消息类
*/
@Data
class Message{
String value;
public Message(String value){
this.value= value;
}
}
/**
* 生产者
*/
class Producer{
private BlockingQueue<Message> queue = null;
public Producer(BlockingQueue<Message> queue) {
this.queue = queue;
}
public void sendMessage(Message m) throws InterruptedException {
queue.put(m);
System.out.println("生产者放入了一个消息@"+ m.getValue());
}
}
/**
* 消费者
* 继承Thread可以给线程设置名称
*/
class Consumer extends Thread{
private BlockingQueue<Message> queue = null;
public Consumer(BlockingQueue<Message> queue) {
this.queue = queue;
}
@SneakyThrows
@Override
public void run() {
while (true){
if(!queue.isEmpty()){
System.out.println(Thread.currentThread().getName()+"消费者获取了消息"+queue.take().getValue());
}
}
}
}
}
ArrayBlockingQueue
运行结果
生产者放入了一个消息@消息@0
线程-1:消费者获取了消息消息@0
生产者放入了一个消息@消息@1
线程-2:消费者获取了消息消息@1
生产者放入了一个消息@消息@2
线程-2:消费者获取了消息消息@2
生产者放入了一个消息@消息@3
线程-2:消费者获取了消息消息@3
生产者放入了一个消息@消息@4
线程-2:消费者获取了消息消息@4
生产者放入了一个消息@消息@5
线程-2:消费者获取了消息消息@5
生产者放入了一个消息@消息@6
线程-2:消费者获取了消息消息@6
生产者放入了一个消息@消息@7
线程-2:消费者获取了消息消息@7
生产者放入了一个消息@消息@8
线程-2:消费者获取了消息消息@8
生产者放入了一个消息@消息@9
线程-2:消费者获取了消息消息@9
LinkedBlockingQueue
运行结果
生产者放入了一个消息@消息@0
线程-2:消费者获取了消息消息@0
生产者放入了一个消息@消息@1
线程-1:消费者获取了消息消息@1
生产者放入了一个消息@消息@2
线程-1:消费者获取了消息消息@2
生产者放入了一个消息@消息@3
线程-2:消费者获取了消息消息@3
生产者放入了一个消息@消息@4
线程-1:消费者获取了消息消息@4
生产者放入了一个消息@消息@5
线程-2:消费者获取了消息消息@5
生产者放入了一个消息@消息@6
线程-1:消费者获取了消息消息@6
生产者放入了一个消息@消息@7
线程-2:消费者获取了消息消息@7
生产者放入了一个消息@消息@8
线程-1:消费者获取了消息消息@8
生产者放入了一个消息@消息@9
线程-2:消费者获取了消息消息@9
ArrayBlockingQueue
在一个消费者线程获取消息后,另一个线程会获取不到,LinkedBlockingQueue
会在两个线程交替获取消息,可能是因为锁机制不同,LinkedBlockingQueue
是双锁,放入和取出锁不同,而ArrayBlockingQueue
是单锁
参考https://www.zhihu.com/question/54152397?sort=created