黑马程序员——多线程操作经典实例:生产者消费者问题
来源:互联网 发布:淘宝客如意投 编辑:程序博客网 时间:2024/05/22 05:21
------- android培训、java培训、期待与您交流! ----------
生产者消费者问题是线程操作中的一个经典案例,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。在同一个进程地址空间内执行的两个线程生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。看了买的教材中对生产者消费者问题的讲解非常的精彩,于是记下此篇日志加深理解并且便于以后复习。
根据需求,我们开始一步步的分析实现:
首先,程序中生产者和消费者都有一个操作的对象,也就是产品,于是我们先定义一个包含产品信息的Product类:
Product.java
package com.itheima;public class Product{private String name;// 定义name属性private String category;// 定义category属性public void setName(String name){this.name = name;}public void setCategory(String category){this.category = category;}public String getName(){return this.name;}public String getCategory(){return this.category;}}
因为生产者和消费者操作的是同一个空间的内容,所以我们让生产者和消费者分别实现Runnable接口以接收Product类的实例。Producer和Consumer类的定义如下:Producer.java
package com.itheima;class Producer implements Runnable{private Product product;public Producer(Product product){this.product = product;}public void run(){boolean flag = false;for(int i=0;i<10;i++){if(flag){this.product.setName("永久");try{Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}this.product.setCategory("自行车");flag = false;}else{this.product.setName("劳斯莱斯");try{Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}this.product.setCategory("汽车");flag = true;}}}}
Consumer.javapackage com.itheima;class Consumer implements Runnable{private Product product;public Consumer(Product product){this.product = product;}public void run(){for(int i=0;i<10;i++){try{Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace() ;}System.out.println(this.product.getName()+ ":"+this.product.getCategory());}}}
然后我们编写测试程序对程序进行检测package com.itheima;public class Test{public static void main(String args[]){Product product = new Product();Producer pro = new Producer(product);Consumer con = new Consumer(product);new Thread(pro).start();new Thread(con).start();}}
运行结果:永久:汽车
劳斯莱斯:自行车
永久:汽车
劳斯莱斯:自行车
永久:汽车
劳斯莱斯:自行车
永久:汽车
劳斯莱斯:自行车
永久:汽车
永久:自行车我们发现乱套了,不仅不像我们开始定义的“永久:自行车”和“劳斯莱斯:汽车”,而且还有重复两次输出“永久”的情况。这是为什么呢?因为生产者和消费者的线程都已启动,这样不能保证谁在前,或者谁在后,在生产者还在设置内容的时候,消费者已经取走了内容,那么显示的肯定就会出现不匹配的结果。而且这两个方法在不同的线程中,当一条线程中的方法设置完内容之后,另一个线程取出内容显示,取完之后继续取,这样生产者无法更新内容,那显示出来的内容就会出现重复。
这个时候,我们就应该定义一个boolean型标记,并使用wait()和notify()方法用来控制他们轮流对资源进行操作,避免因为资源分配不均衡导致的重复输出错误;用synchronized关键字来声明set()和get()方法,把他们定义成一个同步方法,这样便可以避免输出不匹配的结果。改过之后代码如下:
Product.java
package com.itheima;class Product{private String name;private String category;private boolean flag = false;public synchronized void set(String name,String category){if(!flag){try{super.wait();}catch(InterruptedException e){e.printStackTrace();}}this.setName(name);try{Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}this.setCategory(category) ;flag = false;//改变标志位,表示可以取走super.notify();}public synchronized void get(){if(flag){try{super.wait();}catch(InterruptedException e){e.printStackTrace();}}try{Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}System.out.println(this.getName()+":"+this.getCategory());flag = true;//改变标志位,表示可以生产super.notify();}public void setName(String name){this.name = name;}public void setCategory(String category){this.category = category;}public String getName(){return this.name;}public String getCategory(){return this.category;}}Producer.java
package com.itheima;class Producer implements Runnable{private Product product;public Producer(Product product){this.product = product;}public void run(){boolean flag = false;for(int i=0;i<10;i++){if(flag){this.product.set("永久","自行车");flag = false;}else{this.product.set("劳斯莱斯","汽车");flag = true;}}}}Consumer.java
package com.itheima;class Consumer implements Runnable{private Product product;public Consumer(Product product){this.product = product;}public void run(){for(int i=0;i<10;i++){this.product.get();}}}
测试程序保持不变,运行结果:永久:自行车
劳斯莱斯:汽车
永久:自行车
劳斯莱斯:汽车
永久:自行车
劳斯莱斯:汽车
永久:自行车
劳斯莱斯:汽车
永久:自行车
劳斯莱斯:汽车
------- android培训、java培训、期待与您交流! ----------
- 黑马程序员——多线程操作经典实例:生产者消费者问题
- 黑马程序员_多线程:生产者消费者练习实例及问题
- 经典多线程实例:生产者消费者问题
- 黑马程序员----多线程之生产者消费者问题
- 黑马程序员-java多线程生产者消费者问题
- 黑马程序员——Java---多线程-生产者和消费者
- 黑马程序员-多线程经典之消费者与生产者
- 多线程经典——生产者和消费者问题
- 多线程通信经典问题——生产者消费者
- 多线程经典——生产者消费者问题(加锁版)
- 黑马程序员——生产者和消费者问题
- 黑马程序员-多线程(生产者与消费者问题)
- 黑马程序员——生产者消费者详解
- 多线程—生产者于消费者实例
- 经典多线程Java实例 生产者与消费者
- 多线程经典实例;生产者和消费者
- 多线程经典的 生产者-消费者 实例
- 多线程八 生产者消费者经典问题
- Java-可变类和不可变类
- Codeforce172 Div2
- PHP 判断字符的编码 并输出想要的编码格式字符
- C语言的编译器的一点注意
- io流文件的读取
- 黑马程序员——多线程操作经典实例:生产者消费者问题
- SharedPreference自动保存登录信息
- 修改UITableViewStyleGrouped形式的tableview的背景色
- Redis 基础工具函数
- 【计算机经典书籍】(转载)
- 中文按拼音排序
- 黑马程序员 笔记(一)——JAVA概述
- CentOS6.3安装VNC远程桌面【RealVNC5.0】
- EINTR 错误码4