ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

为啥厨师和服务员会打架?--多线程通信问题之生产者和消费者

2021-02-28 22:30:48  阅读:224  来源: 互联网

标签:java ThreadDemo -- Food 厨师 Waiter Cook 多线程 public


概念

是一个典型的多线程通信问题,当生产者生产时,消费者进行休眠;当生产者结束生产,唤醒消费者进行消费,生产者休眠。

在线程调用的类中需要使用同步方法关键字synchronized,这是为了防止两个线程同时使用方法,调用同一个对象中的属性。

实例代码

代码中主要有两个线程,一个叫Cook,一个叫Waiter,他们各自可以调用名为Food的类对象中的一个方法。

Cook和Waiter实现线程的方法是继承Thread类,重写run方法

Cook是厨师,英语中职业类名词唯一不加-er或-or后缀的那个。

问题代码

Cook打算做100份菜,分别是50份玉米糁子和50份宫保鸡丁;Waiter负责在Cook做好以后端走这饭菜。

因为盘子只有一个,所以Cook在Waiter把盘子端回来之前不能做下一份菜,那Cook要怎么办呢?

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Food f = new Food();
        new Cook(f).start();
        new Waiter(f).start();
    }

    public static class Cook extends Thread{
        Food f;
        Cook(Food f){
            this.f = f;
        }

        @Override
        public void run() {
            for(int i =0; i<100; i++){
                if(i%2 ==0){
                    try {
                        f.setNameAndTaste("玉米糁子","甜");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    try {
                        f.setNameAndTaste("宫保鸡丁","香辣");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    static class Waiter extends Thread{
        Food f;
        Waiter(Food f){
            this.f = f;
        }

        @Override
        public void run(){
            for(int i =0; i<100; i++){
                try {
                    f.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    f.get(f);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }       
    }



    public static class Food extends Thread{
        private String name;
        private String taste;

        private boolean flag = true;

        public void setNameAndTaste(String name,  String taste) throws InterruptedException {
            if(flag){
                this.name = name;
                sleep(100);
                this.taste = taste;
                flag =false;
                this.notifyAll();
                this.wait();
            }

        }

        public void get(Food f) throws InterruptedException {
            if(!flag){
                System.out.println("服务员端走了"+f.name+",味道是:"+f.taste);
                flag = true;
                this.notifyAll();
                this.wait();
            }
        }
    }
}

第一次的代码不成功,报错如下

Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
  at java.base/java.lang.Object.notifyAll(Native Method)
  at ThreadDemo.ThreadDemo$Food.setNameAndTaste(ThreadDemo.java:79)
  at ThreadDemo.ThreadDemo$Cook.run(ThreadDemo.java:25)
服务员端走了玉米糁子,味道是:甜
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
  at java.base/java.lang.Object.notifyAll(Native Method)
  at ThreadDemo.ThreadDemo$Food.get(ThreadDemo.java:89)
  at ThreadDemo.ThreadDemo$Waiter.run(ThreadDemo.java:55)

更改代码

更改后的代码如下,注意看注释

   //食物
    static class Food{
        private String name;
        private String taste;

        //true表示可以生产
        private boolean flag = true;
        //setNameAndTaste这个方法需要加上关键字synchronized
        public synchronized void setNameAndTaste(String name,  String taste){
            if(flag){
                this.name = name;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.taste = taste;
                flag =false;
                this.notifyAll();
                try {
                    this.wait();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
        //get也要加上关键字synchronized
        public synchronized void get() {
            if(!flag){
                System.out.println("服务员端走了"+name+",味道是:"+taste);
                flag = true;
                this.notifyAll();
                try {
                    this.wait();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }

需要加关键字的原因在于:

厨师和服务员两个线程调用Food,如果不限制同步方法,厨师会在没有盘子的情况下开始做饭,并导致出错(虽然我也不知道内部究竟怎么回事,为啥只有一个盘子。。)

标签:java,ThreadDemo,--,Food,厨师,Waiter,Cook,多线程,public
来源: https://blog.csdn.net/weixin_43458234/article/details/114241349

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有