引言
之前自己的面試經歷老被問到手寫阻塞隊列,當然大概率情況下面試官不會很直白的就讓你實現一個阻塞隊列,這個問題有很多的變種,但是萬變不離其宗,知道了怎麼去實現阻塞,也就會實現阻塞隊列了。
比如我曾經遇到的面試題:
- 百度一面:兩個線程實現交叉打印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在這裏插入代碼片