生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。
这里实现如下情况的生产--消费模型:
生产者不断交替地生产两组数据“姓名--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