今天是端午節,祝大家端午節快樂。今年的疫情讓很多人放棄了出行的計劃,宅在家裏,我也是無聊,想到寫點什麼東西和大家分享下,希望有感興趣的看看,如果有什麼想法歡迎交流。
生產者和消費者是軟件世界裏很尋常的場景,然而大多數程序員平時寫代碼不會用到,因爲很多系統都是用來查詢數據展示數據,寫寫CRUD就好了。隨着MQ的橫空出世,讓大家都醉心於這種好用的中間件,配置一個Topic,發送消息就調用客戶端的發送接口,接收消息繼承一個接口,寫一個Listener,整個從生產到消費全流程就這種友好的解決了,性能和完整性更不用你擔心,因爲這些主流MQ都號稱是幾十萬的TPS,4個9的可靠性。
凡事需知其然及其所以然,MQ就是一個基於生產者和消費者的最佳實踐。今天想基於阻塞隊列來實現生產者和消費者的場景,阻塞隊列用的是ArrayBlockingQueue,一個生產者線程,一個消費者線程。
生產者代碼
public class Producer implements Runnable {
BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public void run() {
while (true) {
Integer num = Double.valueOf(Math.random()*100).intValue();
this.queue.offer(num);
System.out.println("加入元素到隊列:"+num);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消費者代碼
public class Consumer implements Runnable {
BlockingQueue<Integer> queue;
String name;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public Consumer(String name, BlockingQueue<Integer> queue) {
this.name = name;
this.queue = queue;
}
public void run() {
while (true){
System.out.println("開始隊列長度**********:"+queue.size());
Integer num = this.queue.poll();
System.out.println(name + "消費元素:**********" + num);
System.out.println("結束隊列長度:"+queue.size());
try {
Thread.sleep(120);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
下面創建了一個生產者和二個消費者,因爲生產者生產得快,大家可以先用一個消費者看看結果,會發現消費隊列總會有元素,主要源於生產者生產的速度比消費者快,當增加一個消費者後,就會發現隊列爲空,被消費完了,線程等待的狀況。
public class ConsumerTest {
public static void main(String[] args) {
BlockingQueue<Integer> myQueue = new ArrayBlockingQueue<Integer>(1000);
Thread producer = new Thread(new Producer(myQueue));
Thread consumer = new Thread(new Consumer(myQueue));
Thread consumer2 = new Thread(new Consumer("consumer2", myQueue));
consumer.start();
producer.start();
consumer2.start();
try {
producer.join();
consumer.join();
consumer2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如果隊列滿了,對於ArrayBlockingQueue 的 offer操作來說,會直接丟棄掉插入的元素。如果想驗證,可以將隊列容量修改爲4,然後在生產者中加入下面的代碼,就會打出插入失敗的元素,並且往後看,會發現這個元素不會被消費到。
public void run() {
while (true) {
Integer num = Double.valueOf(Math.random()*100).intValue();
String isSuccess = this.queue.offer(num) ? "成功":"失敗";
System.out.println("加入元素到隊列:"+ num +" " + isSuccess );
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
今天和大家聊了下生產者和消費者,相信大家已經大致明白了整個的過程,爲大家模擬了單生產者多消費者的例子,大家也可以自己去擴展多生產者和多消費者。說到這裏,還是想拋磚引玉,這個隊列例子和MQ隊列相比有哪些不足,MQ有哪些黑科技爲大型分佈式系統保駕護航。