设计模式06---生产者消费者模式

生产者和消费者指的是两个不同的线程类对象,操作统一资源的情况。具体的操作流程如下:

(1)生产者负责生成数据,消费者负责取走数据;

(2)生产者每生产完一组数据之后,消费者就要取走一组数据。

一. 直白写法

1. info类

 1 public class Info {
 2     private String name;
 3     private double price;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public double getPrice() {
11         return price;
12     }
13     public void setPrice(double price) {
14         this.price = price;
15     }
16 
17 }
View Code

2. 生产者类

 1 public class Producer implements Runnable{
 2     private Info info;
 3     public Producer(Info info) {
 4         this.info=info;
 5     }
 6     
 7     @Override
 8     public void run() {
 9         for(int i=0;i<20;i++) {
10             if(i%2==0) {
11                 this.info.setName("铅笔");
12                 try {
13                     Thread.sleep(100);
14                 } catch (InterruptedException e) {
15                     // TODO Auto-generated catch block
16                     e.printStackTrace();
17                 }
18                 this.info.setPrice(1.0);
19             }else {
20                 this.info.setName("LV");
21                 try {
22                     Thread.sleep(100);
23                 } catch (InterruptedException e) {
24                     // TODO Auto-generated catch block
25                     e.printStackTrace();
26                 }
27                 this.info.setPrice(10000.0);
28             }
29         }
30     }
31 
32 }
View Code

3. 消费者类

 1 public class Consumer implements Runnable{
 2     private Info info;
 3     public Consumer(Info info) {
 4         this.info=info;
 5     }
 6     @Override
 7     public void run() {
 8         for(int i=0;i<20;i++) {
 9             try {
10                 Thread.sleep(100);
11             } catch (InterruptedException e) {
12                 // TODO Auto-generated catch block
13                 e.printStackTrace();
14             }
15             System.out.println(this.info.getName()+"----"+this.info.getPrice());
16         }    
17     }
18 }
View Code

4. 测试类

1 public class Test {
2     public static void main(String[] args) {
3         Info info=new Info();
4         new Thread(new Producer(info)).start();
5         new Thread(new Consumer(info)).start();
6     }
7 }
View Code
 1 LV----1.0
 2 铅笔----10000.0
 3 铅笔----1.0
 4 铅笔----10000.0
 5 铅笔----1.0
 6 LV----1.0
 7 铅笔----1.0
 8 LV----10000.0
 9 铅笔----1.0
10 LV----1.0
11 铅笔----1.0
12 LV----10000.0
13 铅笔----10000.0
14 LV----10000.0
15 铅笔----10000.0
16 LV----10000.0
17 铅笔----1.0
18 LV----1.0
19 铅笔----1.0
20 LV----10000.0
View Code

说明:上面添加了sleep方法,是为了更好的观察分析存在的问题。根据测试结果我们可以知道,有两个很严重的问题。第一个是数据错乱,比如铅笔对应的是10000;第二个是数据重复设置,比如铅笔连着打印了几次。不符合生产一个,然后再消费一个的标准。因此,需要进行改进。

二. 解决数据错乱

数据的错乱完全是因为非同步的操作完成的,所以应该使用同步处理。因为取和设置是两个不同的操作,要想进行同步操作,因此需要将它们定义再一个类里面。

1. info类

 1 public class Info {
 2     private String name;
 3     private double price;
 4     public synchronized void set(String name,double price) {
 5         this.name=name;
 6         try {
 7             Thread.sleep(100);
 8         } catch (InterruptedException e) {
 9             // TODO Auto-generated catch block
10             e.printStackTrace();
11         }
12         this.price=price;
13     }
14     
15     public synchronized void get() {
16         try {
17             Thread.sleep(100);
18         } catch (InterruptedException e) {
19             // TODO Auto-generated catch block
20             e.printStackTrace();
21         }
22         System.out.println(this.name+"---------"+this.price);
23     }
24 
25 }
View Code

2.生产者

 1 public class Producer implements Runnable{
 2     private Info info;
 3     public Producer(Info info) {
 4         this.info=info;
 5     }
 6     
 7     @Override
 8     public void run() {
 9         for(int i=0;i<20;i++) {
10             if(i%2==0) {
11                 this.info.set("铅笔", 1.0);
12             }else {
13                 this.info.set("LV", 10000.0);
14             }
15         }
16     }
17 
18 }
View Code

3.消费者

 1 public class Consumer implements Runnable{
 2     private Info info;
 3     public Consumer(Info info) {
 4         this.info=info;
 5     }
 6     @Override
 7     public void run() {
 8         for(int i=0;i<20;i++) {
 9             this.info.get();
10         }    
11     }
12 }
View Code

4. 测试类

1 public class Test {
2     public static void main(String[] args) {
3         Info info=new Info();
4         new Thread(new Producer(info)).start();
5         new Thread(new Consumer(info)).start();
6     }
7 }
View Code
 1 铅笔---------1.0
 2 铅笔---------1.0
 3 LV---------10000.0
 4 LV---------10000.0
 5 LV---------10000.0
 6 LV---------10000.0
 7 LV---------10000.0
 8 铅笔---------1.0
 9 铅笔---------1.0
10 铅笔---------1.0
11 LV---------10000.0
12 LV---------10000.0
13 铅笔---------1.0
14 铅笔---------1.0
15 铅笔---------1.0
16 LV---------10000.0
17 LV---------10000.0
18 铅笔---------1.0
19 铅笔---------1.0
20 铅笔---------1.0
View Code

说明:现在数据错乱的问题解决了,但是数据重复设置的问题更严重了。需要进一步解决

三. 解决重复设置问题

解决重复设置问题就需要有一个标志位来告诉是该生产还是是该消费。比如下面修改就可以解决:

1. Info类

 1 package com.test.b;
 2 
 3 public class Info {
 4     private String name;
 5     private double price;
 6     private boolean flag=true;
 7     //flag=true:表示可以生产,但是不可以取走
 8     //flag=false:表示可以取走,但是不可以生产
 9     public synchronized void set(String name,double price) {
10         //重复进入到了set()方法里面,发现不能够生产,因此需要进行等待
11         if(flag==false) {
12             try {
13                 super.wait();
14             } catch (InterruptedException e) {
15                 // TODO Auto-generated catch block
16                 e.printStackTrace();
17             }
18         }
19         this.name=name;
20         try {
21             Thread.sleep(100);
22         } catch (InterruptedException e) {
23             // TODO Auto-generated catch block
24             e.printStackTrace();
25         }
26         this.price=price;
27         this.flag=false;//修改生产标记,说明设置完毕,现在可以进行消费了
28         super.notify();//唤醒其它等待线程
29     }
30     
31     public synchronized void get() {
32         if(this.flag==true) {//还没生产呢,但是进入到了get方法里面来,需要等待
33             try {
34                 super.wait();
35             } catch (InterruptedException e) {
36                 // TODO Auto-generated catch block
37                 e.printStackTrace();
38             }
39         }
40         try {
41             Thread.sleep(100);
42         } catch (InterruptedException e) {
43             // TODO Auto-generated catch block
44             e.printStackTrace();
45         }
46         System.out.println(this.name+"---------"+this.price);
47         this.flag=true;//消费完毕,说明现在可以进行生产了
48         super.notify();
49     }
50 
51 }
View Code

2. 生产者

 1 public class Producer implements Runnable{
 2     private Info info;
 3     public Producer(Info info) {
 4         this.info=info;
 5     }
 6     
 7     @Override
 8     public void run() {
 9         for(int i=0;i<20;i++) {
10             if(i%2==0) {
11                 this.info.set("铅笔", 1.0);
12             }else {
13                 this.info.set("LV", 10000.0);
14             }
15         }
16     }
17 
18 }
View Code

3. 消费者

 1 public class Consumer implements Runnable{
 2     private Info info;
 3     public Consumer(Info info) {
 4         this.info=info;
 5     }
 6     @Override
 7     public void run() {
 8         for(int i=0;i<20;i++) {
 9             this.info.get();
10         }    
11     }
12 }
View Code

4. 测试

1 public class Test {
2     public static void main(String[] args) {
3         Info info=new Info();
4         new Thread(new Producer(info)).start();
5         new Thread(new Consumer(info)).start();
6     }
7 }
View Code
 1 铅笔---------1.0
 2 LV---------10000.0
 3 铅笔---------1.0
 4 LV---------10000.0
 5 铅笔---------1.0
 6 LV---------10000.0
 7 铅笔---------1.0
 8 LV---------10000.0
 9 铅笔---------1.0
10 LV---------10000.0
11 铅笔---------1.0
12 LV---------10000.0
13 铅笔---------1.0
14 LV---------10000.0
15 铅笔---------1.0
16 LV---------10000.0
17 铅笔---------1.0
18 LV---------10000.0
19 铅笔---------1.0
20 LV---------10000.0
View Code

Note:生产者和消费者都需要实现Runnable接口。

 

转载于:https://www.cnblogs.com/Hermioner/p/10029581.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值