• Java线程——线程习题(二)生成者消费者


    生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。

        这里实现如下情况的生产--消费模型:

        生产者不断交替地生产两组数据“姓名--1 --> 内容--1”,“姓名--2--> 内容--2”,消费者不断交替地取得这两组数据,这里的“姓名--1”和“姓名--2”模拟为数据的名称,“内容--1 ”和“内容--2 ”模拟为数据的内容。

         由于本程序中牵扯到线程运行的不确定性,因此可能会出现以下问题:

         1、假设生产者线程刚向数据存储空间添加了数据的名称,还没有加入该信息的内容,程序就切换到了消费者线程,消费者线程将把信息的名称和上一个信息的内容联系在一起;

         2、生产者生产了若干次数据,消费者才开始取数据,或者是,消费者取完一次数据后,还没等生产者放入新的数据,又重复取出了已取过的数据。

         问题1很明显要靠同步来解决,问题2则需要线程间通信,生产者线程放入数据后,通知消费者线程取出数据,消费者线程取出数据后,通知生产者线程生产数据,这里用wait/notify机制来实现。

    代码如下:

    package com.itheima.gan;
    
    //信息类
    class Info{
        private String name="name";  //定义name属性,与下面set方法里的name属性分开
        private String content="content";  //定义content属性,与下mianset的content属性区分开
        
        private boolean flag=true; //设置标识位,初始时生成
        
        
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
    
    
    
        //设置值
        public synchronized void set(String name,String content) {
            //如果标识位true,就不等待,标识为false,就等待
            while(!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            this.setName(name); //设置名称
            
            //休眠0.3s,再执行设置内容
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.setContent(content);
            
            //设置标识为false,表示可以取走
            flag=false;
            super.notify();
        }
        
        
        //取走值
        public synchronized void get() {
            //如果标识为true,表示现在时放入值的时候,消费者将等待
            while(flag) {
                try {
                    super.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            //可以取值的时候先休眠0.3s
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            //取值
            System.out.println(this.getName()+">=="+this.getContent());
            //去完值后设置标识位为true
            flag=true;
            //唤醒其他等待的线程
            super.notify();
        }    
    
    }
    
    //生产者
    class Producer implements Runnable{
    
        private Info info=null;
        
        //构造方法
        public Producer(Info info) {
            this.info=info;
        }
        
        @Override
        public void run() {
            //设置一个标识位为true
            boolean flag=true;
            
            for(int i=0;i<10;i++) {
                
                //如果标识位为true,添加内容1
                //如果标识位为false,添加内容2
                if(flag) {
                    this.info.set("姓名1", "内容1");
                    //将标识位改为false
                    flag=false;
                }else {
                    this.info.set("姓名2", "内容2");
                    flag=true;
                }
            }
            
        }
        
    }
    
    //消费者
    class Cusumer implements Runnable{
        private Info info=null;
        public Cusumer(Info info) {
            this.info=info;
        }
        @Override
        public void run() {
            for(int i=0;i<10;i++) {
                this.info.get();
            }
            
            
        }
        
    }
    
    public class ProducerAndConsumerThread {
        public static void main(String[] args) {
            Info info=new Info();
            
            Producer producer =new Producer(info);
            Cusumer cusumer=new Cusumer(info);
            //启动生成者
            new Thread(producer).start();
            
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            //启动消费者
            new Thread(cusumer).start();
        }
    }

      运行结果:

    另外,在run方法中,二者循环的次数要相同,否则,当一方的循环结束时,另一方的循环依然继续,它会阻塞在wait()方法处,而等不到对方的notify通知。


    ————————————————
    版权声明:本文为CSDN博主「兰亭风雨」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/ns_code/article/details/17249321

  • 相关阅读:
    vim编辑器替换以及全局替换
    Linux下grep显示前后几行信息
    Pymol里常用到的命令,随用随记
    硬盘里有文件错误,导致删除不了文件,可以使用如下方法
    解决Host key verification failed
    tcl语言杂记
    python脚本后台运行的几种方式
    centos设置连续登录3次密码错误自动锁定账户3分钟
    ubuntu安装显卡驱动
    虚拟交换机(OVS)之结构印象
  • 原文地址:https://www.cnblogs.com/zhilili/p/11972001.html
Copyright © 2020-2023  润新知