溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java多線程中的生產(chǎn)者與消費者案例講解

發(fā)布時間:2021-07-28 09:07:18 來源:億速云 閱讀:100 作者:chen 欄目:開發(fā)技術

這篇文章主要講解了“Java多線程中的生產(chǎn)者與消費者案例講解”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java多線程中的生產(chǎn)者與消費者案例講解”吧!

目錄
  • 前言

    • 工具

    • 知識點

    • 設計思路

    • 具體步驟

  • 總結

    前言

    想象一下生活中哪些是和線程沾邊的?飯店炒菜就是一個很好的例子

    首先客人要吃菜,前提是廚師要炒好,也就是說,廚師不炒好的話客人是沒有飯菜的。這時候,廚師就是一個線程,客人拿菜就是另一個線程。

    工具

    jdk13,IDEA2019.1.4

    知識點

    Thread、Runnable、synchronized、面向對象知識(繼承、封裝、接口、方法重寫)、條件判斷以及線程的一些其他知識點

    設計思路

    首先要有兩個線程,也就是說要兩個類,分別是Producer(生產(chǎn)者)和Consumer(消費者)。

    由于我們是模擬廚師與客人之間的互動,也就是說還需要一個類來封裝信息:Message(類)。

    然后,避免線程之間發(fā)生數(shù)據(jù)混亂的情況,肯定還需要使用synchronized來進行線程同步。

    具體步驟

    首先我們來一份沒有用synchronized的代碼,先看看效果:

    public class Message {
        private String title;
        private String content;
        Message(){
        };
        public Message(String title, String content) {
            this.title = title;
            this.content = content;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
    }
    /*
    * 定義生產(chǎn)者類Producer
    * */
    class Producer implements Runnable{
        private Message msg=null;
        public Producer(Message msg) {
            this.msg = msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                if (i%2==0){
                    this.msg.setTitle("喜歡夜雨嗎?");
                    try {
                        Thread.sleep(100);
                    }catch (InterruptedException e){
                        System.out.println(e);
                    }
                    this.msg.setContent("是的呢!");
                }else {
                    this.msg.setTitle("還不關注我嗎?");
                    try {
                        Thread.sleep(100);
                    }catch (InterruptedException e){
                        System.out.println(e);
                    }
                    this.msg.setContent("好的呢!");
                }
            }
        }
    }
    /*
    * 定義消費者類Consumer
    * */
    class Consumer implements Runnable{
        private Message msg=null;
        public Consumer(Message msg) {
            this.msg = msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                try {
                    Thread.sleep(100);
                }catch (InterruptedException e){
                    System.out.println(e);
                }
                System.out.println(this.msg.getTitle()+"--->"+this.msg.getContent());
            }
        }
    }
    class TestDemo{
        public static void main(String[] args) {
            Message msg=new Message();
            new Thread(new Producer(msg)).start();
            new Thread(new Consumer(msg)).start();
        }
    }

    看看運行結果:

    Java多線程中的生產(chǎn)者與消費者案例講解

    看仔細咯,發(fā)生了數(shù)據(jù)錯亂啊,Title與Content沒有一一對應欸。咋辦?

    能咋辦,改代碼唄。

    發(fā)生數(shù)據(jù)混亂的原因完全是因為,生產(chǎn)者線程還沒生產(chǎn)的時候,消費者就已經(jīng)消費了(至于消費的啥我也不知道,我也不敢問啊)。所以造成了數(shù)據(jù)混亂,不過我們上面說了啊,要使用synchronized來讓線程同步一下。但是又會出問題,我們接著往下看

    class TestDemo{
        public static void main(String[] args) {
            Message msg=new Message();
            new Thread(new Producer(msg)).start();
            new Thread(new Consumer(msg)).start();
        }
    }
    class Message{
        private String title,content;
        public synchronized void set(String title,String content){
            this.title=title;
            this.content=content;
        }
        public synchronized void get(){
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){
                System.out.println(e);
            }
            System.out.println(this.title+"-->"+this.content);
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
    }
    class Producer implements Runnable{
        private Message msg=null;
        Producer(Message msg){
            this.msg=msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                if (i%2==0){
                    this.msg.set("喜歡夜雨嗎?","是的呢!");
                }else {
                    this.msg.set("還不關注嗎?","好的呢!");
                }
            }
        }
    }
    class Consumer implements Runnable{
        private Message msg=null;
        Consumer(Message msg){
            this.msg=msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                this.msg.get();
            }
        }
    }

    我又重新封裝了一些方法,然后運行的時候,wc,數(shù)據(jù)倒是不混亂了,但是呢,數(shù)據(jù)重復了一大堆。

    Java多線程中的生產(chǎn)者與消費者案例講解

    為啥會出現(xiàn)這個問題呢?最后想了一下,會出現(xiàn)這種問題的,就是因為線程的執(zhí)行順序的問題。我們想要實現(xiàn)的效果是生產(chǎn)者線程執(zhí)行了之后,讓生產(chǎn)者線程等待,而后讓消費者線程執(zhí)行,等待消費者線程執(zhí)行完成之后就又讓生產(chǎn)者線程繼續(xù)執(zhí)行。后來我又查了查官方文檔,發(fā)現(xiàn)Object類中專門有三個方法是與線程相關的:

    方法描述
    public final void wait() throws InterruptedException線程的等待
    public final void notify()喚醒第一個等待線程
    public final void notifyAll()

    當我看到這些方法的時候,心里愣了一下,這不就是我們想要的方法嗎,用wait()方法來讓生產(chǎn)者線程等待,然后運行消費者線程,等消費者線程執(zhí)行完了之后又讓生產(chǎn)者線程去執(zhí)行。這其中我們用true和false來表示運行開始和運行暫停。

    最后我們來看看完成品的代碼:

    class TestDemo{
        public static void main(String[] args) {
            Message msg=new Message();
            new Thread(new Producer(msg)).start();
            new Thread(new Consumer(msg)).start();
        }
    }
    class Message extends Exception{
        private String title,content;
        private boolean flag=true;
        // true表示正在生產(chǎn),不要來取走,因為沒由讓消費者區(qū)走的
        // false表示可以取走,但是不能生產(chǎn)
        public synchronized void set(String title,String content){
            if (this.flag==false){
                try {
                    super.wait();
                }catch (InterruptedException e){
                    System.out.println(e);
                }
            }
            this.title=title;
            try {
                Thread.sleep(60);
            }catch (InterruptedException e){
                System.out.println(e);
            }
            this.content=content;
            this.flag=true; // 生產(chǎn)完成,修改標志位
            super.notify(); // 喚醒等待線程
        }
        public synchronized void get(){
            if (flag==true) {// 已經(jīng)生產(chǎn)好了,等待取走
                try {
                    super.wait();
                }catch (InterruptedException e){
                    System.out.println(e);
                }
            }
            try {
                Thread.sleep(60);
            }catch (InterruptedException e){
                System.out.println(e);
            }
            System.out.println(this.title+"-->"+this.content);
            this.flag=true;
            super.notify();
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
    }
    class Producer implements Runnable{
        private Message msg=null;
        Producer(Message msg){
            this.msg=msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                if (i%2==0){
                    this.msg.set("喜歡夜雨嗎?","是的呢!");
                }else {
                    this.msg.set("還不關注嗎?","好的呢!");
                }
            }
        }
    }
    class Consumer implements Runnable{
        private Message msg=null;
        Consumer(Message msg){
            this.msg=msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                this.msg.get();
            }
        }
    }

    運行結果我就不貼了,你們自己去測試一下吧…

    總結

    這個案例完美的呈現(xiàn)了線程以及面向對象知識的綜合運用,具有很強的實際操作性

    感謝各位的閱讀,以上就是“Java多線程中的生產(chǎn)者與消費者案例講解”的內容了,經(jīng)過本文的學習后,相信大家對Java多線程中的生產(chǎn)者與消費者案例講解這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

    AI