濃濃棕情之自產自消

今天是端午節,祝大家端午節快樂。今年的疫情讓很多人放棄了出行的計劃,宅在家裏,我也是無聊,想到寫點什麼東西和大家分享下,希望有感興趣的看看,如果有什麼想法歡迎交流。

生產者和消費者是軟件世界裏很尋常的場景,然而大多數程序員平時寫代碼不會用到,因爲很多系統都是用來查詢數據展示數據,寫寫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有哪些黑科技爲大型分佈式系統保駕護航。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章