原理:使用jvm锁机制和一个普通队列共同实现一个阻塞队列
package com.es.demo;
import lombok.extern.slf4j.Slf4j;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 使用多线程实现一个阻塞队列
*
* @author renpl
*/
@Slf4j
public class MyBlockQueue {
// 初始化一个普通队列
private final LinkedList<Object> list = new LinkedList<>();
// 初始化一个计数器用于记录集合中添加的元素
private final AtomicInteger counter = new AtomicInteger();
// 初始化队列元素的最小数
private int minSize = 0;
// 初始化队列元素的最大数
private int maxSize;
// 初始化一个对象,用于加锁
private Object lock = new Object();
// 构造函数初始化一个制定大小的队列
public MyBlockQueue(int maxSize) {
this.maxSize = maxSize;
}
/**
* 阻塞队列添加方法
*
* @param obj
* @throws InterruptedException
*/
private void put(Object obj) {
try {
synchronized (lock) {
while (maxSize == counter.get()) {
log.debug("队列已满");
lock.wait();
}
// 队列中添加元素
list.add(obj);
// 计数器加1
counter.incrementAndGet();
// 唤醒其他正在排队向队列中添加元素的线程
lock.notify();
}
} catch (InterruptedException e) {
log.error("队列中添加元素发生异常", e);
}
}
/**
* 阻塞队列获取并移除元素
*
* @return
* @throws InterruptedException
*/
private Object take() {
try {
synchronized (lock) {
while (minSize == counter.get()) {
log.debug("此时队列中没有元素");
lock.wait();
}
// 获取队列中的元素并且从队列中移除
Object obj = list.removeFirst();
// 计数器减1
counter.decrementAndGet();
// 唤醒其他正在排队从队列中获取元素的线程
lock.notify();
return obj;
}
} catch (InterruptedException e) {
log.error("获取并移除队列中元素发生异常", e);
}
return null;
}
/**
* 测试
*
* @param args
*/
public static void main(String[] args) {
// 主线程先把队列填满
MyBlockQueue blockQueue = new MyBlockQueue(2);
blockQueue.put("one");
blockQueue.put("two");
// 启动一个线程向填满的队列中新添加元素
new Thread(new Runnable() {
@Override
public void run() {
log.info("新添加的元素:three");
blockQueue.put("three");
}
}).start();
// 获取并移除队列的元素,从而让上一个线程向队列中添加元素
new Thread(new Runnable() {
@Override
public void run() {
String item = (String) blockQueue.take();
log.info("获取到队列的元素:{}", item);
}
}).start();
}
}
运行结果:
09:56:56.848 [Thread-0] DEBUG com.es.demo.MyBlockQueue - 队列已满
09:56:56.851 [Thread-0] INFO com.es.demo.MyBlockQueue - 新添加的元素:three
09:56:56.851 [Thread-1] INFO com.es.demo.MyBlockQueue - 获取到队列的元素:one
执行流程分析:主线程向blockQueue队列中添加了one,two两个元素,此时blockQueue队列已满;
线程Thread-0再次在09:56:56.848时刻向blockQueue中添加元素three,此时队列已阻塞了,控制台打印:
队列已满;这时候线程Thread-1在09:56:56.851时刻从队列中获取并移除one元素,同一时刻线程Thread-0
被唤醒向blockQueue中添加元素three,由于线程Thread-0执行的比线程Thread-1快,所以one元素被移除后
立马就添加元素three,打印:新添加的元素:three,最后又切换至线程Thread-1,执行打印:获取到队列的元素:one