BlockingDeque为先入先出双端队列,意思就是可以从该队列的头部和尾部同时获取数据,和上一篇的单端队列有所不同,适用场景也不同。
一、适用场景
该队列适用于生产消费者模型,与上一篇的不同之处在于,每个消费者会有一个属于自己的产品队列,但又会将其他消费者的产品队列作为备用,以便在自己消费完自己队列里的数据之后,可以继续消费其他队列的数据。这样就起到了加快数据处理的作用。
一般为了避免多线程的锁竞争,消费者消费自己产品队列是从头部取,消费别人的队列从尾部取。
二、demo案例
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 阻塞先入先出双端队列
*/
public class BlockingDequeDemo {
/**
* 消费者
*/
static class Consumer implements Runnable{
//当前消费者名称
private final String name;
//当前消费者的队列
private final BlockingDeque<String> deque;
//其他消费者名称
private final String otherName;
//其他消费者的队列
private final BlockingDeque<String> otherDeque;
//每隔interva1Ms毫秒消费一个产品
private int interva1Ms;
public Consumer(String name,BlockingDeque<String> deque,String otherName,BlockingDeque<String> otherDeque,int interva1Ms){
this.name = name;
this.interva1Ms = interva1Ms;
this.deque = deque;
this.otherName = otherName;
this.otherDeque = otherDeque;
}
@Override
public void run() {
try {
while(true){
//消费自己的队列
String product = deque.pollFirst();
if(product != null){
consume(product);
Thread.sleep(interva1Ms);
continue;
}
//消费其他队列
String otherProduct = otherDeque.pollLast();
if(otherProduct != null){
System.out.println(name+"从"+otherName+"窃取数据");
consume(otherProduct);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 消费行为
* @param product 产品
*/
private void consume(String product){
System.out.println(name +"消费:"+product);
}
}
/**
* 生产者
*/
static class Producer implements Runnable{
//消费者名称
private final String consumerName;
//数据存储队列
private final BlockingQueue queue;
//产品序列号
private final AtomicInteger productSeq;
public Producer(String consumerName,BlockingQueue queue,AtomicInteger productSeq){
this.consumerName = consumerName;
this.queue = queue;
this.productSeq = productSeq;
}
@Override
public void run() {
try {
for(int i =0;i<20;i++){
queue.put(product());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String product(){
return "产品-"+productSeq.incrementAndGet()+" ;所属消费者应为: " + consumerName;
}
}
public static void main(String[] args) {
//消费者1,消费速度比较快的队列。
BlockingDeque<String> deque1 = new LinkedBlockingDeque<>();
//为消费者1生产产品,并存在队列中。
Producer producer1 = new Producer("消费者1",deque1,new AtomicInteger(0));
//消费者2,消费速度比较慢的队列
BlockingDeque deque2 = new LinkedBlockingDeque();
//为消费者2生产产品,并存在队列中
Producer producer2 = new Producer("消费者2",deque2,new AtomicInteger(0));
//消费者1,所属队列为deque1,若消费者1消费的快,可从deque2中窃取数据消费
Consumer consumer1 = new Consumer("消费者1",deque1,"消费者2",deque2,2000);
//消费者2,所属队列为deque2,若消费者2消费的快,可从deque1中窃取数据消费,因为消费间隔时间为4000毫秒,肯定是消费慢的。
Consumer consumer2 = new Consumer("消费者2",deque2,"消费者1",deque1,4000);
new Thread(producer1).start();
new Thread(producer2).start();
//等待生产者完成生产
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(consumer1).start();
new Thread(consumer2).start();
}
}