引言
之前自己的面试经历老被问到手写阻塞队列,当然大概率情况下面试官不会很直白的就让你实现一个阻塞队列,这个问题有很多的变种,但是万变不离其宗,知道了怎么去实现阻塞,也就会实现阻塞队列了。
比如我曾经遇到的面试题:
- 百度一面:两个线程实现交叉打印1-10000
- 菜鸟二面:要是让你用数组实现一个阻塞队列该怎么实现(ArrayBlockQueue)
- 快手一面:手写阻塞队列的add 和take方法
虽然工作中大都是通过使用JUC包中的类来实现咱们的阻塞队列需求,但是了解其原理还是相当重要的。
下面参考上帝爱吃苹果的博客实现一个阻塞队列
public class ZerahBlockQueue {
//队列容器
private List<Integer> container = new ArrayList<>();
private Lock lock = new ReentrantLock();
//Condition
// 队列为空
private Condition isNull = lock.newCondition();
// 队列已满
private Condition isFull = lock.newCondition();
private volatile int size;
private volatile int capacity;
ZerahBlockQueue(int cap) {
this.capacity = cap;
}
public void add(int data) {
try {
lock.lock();
try {
while (size >= capacity) {
System.out.println("队列已满,释放锁,等待消费者消费数据");
isFull.await();
}
} catch (InterruptedException e) {
isFull.signal();
e.printStackTrace();
}
++size;
container.add(data);
isNull.signal();
} finally {
lock.unlock();
}
}
public int take(){
try {
lock.lock();
try {
while (size == 0){
System.out.println("阻塞队列空了,释放锁,等待生产者生产数据");
isNull.await();
}
}catch (InterruptedException e){
isFull.signal();
e.printStackTrace();
}
--size;
int res = container.get(0);
container.remove(0);
isFull.signal();
return res ;
}finally {
lock.unlock();
}
}
}
测试:
public class MyBlockQueueTest {
public static void main(String[] args) {
ZerahBlockQueue queue = new ZerahBlockQueue(5);
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
queue.add(i);
System.out.println("拉个:" + i);
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
for(;;){
System.out.println("屎壳郎开始工作,消费:" + queue.take());
try {
Thread.sleep(800);
}catch (InterruptedException e){
e.printStackTrace();
}
}
});
thread1.start();
thread2.start();
}
}
部分结果:
屎壳郎开始工作,消费:0
拉个:1
屎壳郎开始工作,消费:1
拉个:2
拉个:3
屎壳郎开始工作,消费:2
拉个:4
屎壳郎开始工作,消费:3
拉个:5
拉个:6
屎壳郎开始工作,消费:4
拉个:7
屎壳郎开始工作,消费:5
拉个:8
拉个:9
屎壳郎开始工作,消费:6
拉个:10
拉个:11
屎壳郎开始工作,消费:7
拉个:12
屎壳郎开始工作,消费:8
拉个:13
队列已满,释放锁,等待消费者消费数据
屎壳郎开始工作,消费:9
拉个:14
队列已满,释放锁,等待消费者消费数据
屎壳郎开始工作,消费:10
一定要重视,一定要重视,一定要重视!!!
参考:
1.java 并发队列 BlockingQueue:
https://javadoop.com/post/java-concurrent-queue
2.详解Condition的await和signal等待/通知机制
https://juejin.im/post/5aeea5e951882506a36c67f0在这里插入代码片