生产者与消费者(综合案例)

基础模型:

  生产者和消费者是一道最为经典的供求案例,而想这供求案例:provider、consumer 在以后进行各种分布式结构开发之后都会被大量采用

  现在假设说目的:生产者负责生产一个完整的数据之后,消费者就要把这些数据取走。于是现在假设生产如下的数据:

    title=老李 note=是个好人

    title=名族败类 note=老方B

范例:编写程序的基础模型

 1 package cn.Tony.demo;
 2 public  class TestDemo {
 3     public static void main(String[] args) throws Exception {
 4         Data data=new Data();
 5         new Thread(new DataProvider(data)).start();
 6         new Thread(new DataConsumer(data)).start();
 7     }
 8 }
 9 class DataProvider implements Runnable{
10     private Data data;
11     public DataProvider(Data data) {
12         this.data=data;
13     }
14     @Override
15     public void run() {
16         for(int x=0;x<50;x++) {
17             if(x%2==0) {
18                 this.data.setTitle("老李");
19                 try {
20                     Thread.sleep(1000);
21                 } catch (InterruptedException e) {
22                     e.printStackTrace();
23                 }
24                 this.data.setNote("是个好人");
25             }else {
26                 this.data.setTitle("民族败类");
27                 try {
28                     Thread.sleep(1000);
29                 } catch (InterruptedException e) {
30                     e.printStackTrace();
31                 }
32                 this.data.setNote("老方b");
33             }
34         }
35     }
36 }
37 class DataConsumer implements Runnable{
38     private Data data;
39     public DataConsumer(Data data) {
40         this.data=data;
41     }
42     @Override
43     public void run() {
44         for(int x=0;x<50;x++) {
45             try {
46                 Thread.sleep(1000);
47             } catch (InterruptedException e) {
48                 // TODO Auto-generated catch block
49                 e.printStackTrace();
50             }
51             System.out.println(this.data.getTitle()+"="+this.data.getNote());
52         }
53     } 
54 }
55 class Data{//负责数据保存
56     private String title;
57     private String note;
58     public void setNote(String note) {
59         this.note=note;
60     }
61     public String getNote() {
62         return this.note;
63     }
64     public void setTitle(String title) {
65         this.title=title;
66     }
67     public String getTitle() {
68         return this.title;
69     }
70 }
71  

  这个时候就已经可以发现程序出现两类问题:

    数据不完整,明明是好人,结果成败类

    数据的重复操作问题(重复设置,或重复取出)

解决重复问题

  如果要想解决同步问题,那么可以立刻想到使用synchronized关键字来定义同步的操作方法,所以代码修改如下:

 1 package cn.Tony.demo;
 2 public  class TestDemo {
 3     public static void main(String[] args) throws Exception {
 4         Data data=new Data();
 5         new Thread(new DataProvider(data)).start();
 6         new Thread(new DataConsumer(data)).start();
 7     }
 8 }
 9 class DataProvider implements Runnable{
10     private Data data;
11     public DataProvider(Data data) {
12         this.data=data;
13     }
14     @Override
15     public void run() {
16         for(int x=0;x<50;x++) {
17             if(x%2==0) {
18                 this.data.set("老李","老李是个好人");
19                 
20             }else {
21                 this.data.set("民族败类","老放b");
22             }
23         }
24     }
25 }
26 class DataConsumer implements Runnable{
27     private Data data;
28     public DataConsumer(Data data) {
29         this.data=data;
30     }
31     @Override
32     public void run() {
33         for(int x=0;x<50;x++) {
34             this.data.get();
35         }
36     } 
37 }
38 class Data{//负责数据保存
39     private String title;
40     private String note;
41     public synchronized void get() {
42         try {
43             Thread.sleep(50);
44         } catch (InterruptedException e) {
45             // TODO Auto-generated catch block
46             e.printStackTrace();
47         }
48         System.out.println(this.title+"="+this.note);
49     }
50     public synchronized void set(String title,String note) {
51         this.title=title;
52         try {
53             Thread.sleep(100);
54         } catch (InterruptedException e) {
55             // TODO Auto-generated catch block
56             e.printStackTrace();
57         }
58         this.note=note;
59     }
60 }
61  

  于是现在发现,整个的程序里面数据的同步问题得到了很好的,但是重复操作的问题更加严重了,

解决数据的重复操作问题:

  如果想要解决重复问题,就要添加唤醒和等待机制,如果想使用这一个功能,那么就要参考Object类中的方法。

  等待 死等:public final void wait()throws InterruptedException

  唤醒第一个等待线程:public final void notify()

  唤醒全部等待线程,那 个优先级高,谁有可能先执行:public final void notifyAll()

范例:通过等待和唤醒机制解决重复操作问题

 1 package cn.Tony.demo;
 2 public  class TestDemo {
 3     public static void main(String[] args) throws Exception {
 4         Data data=new Data();
 5         new Thread(new DataProvider(data)).start();
 6         new Thread(new DataConsumer(data)).start();
 7     }
 8 }
 9 class DataProvider implements Runnable{
10     private Data data;
11     public DataProvider(Data data) {
12         this.data=data;
13     }
14     @Override
15     public void run() {
16         for(int x=0;x<50;x++) {
17             if(x%2==0) {
18                 this.data.set("老李","老李是个好人");
19                 
20             }else {
21                 this.data.set("民族败类","老放b");
22             }
23         }
24     }
25 }
26 class DataConsumer implements Runnable{
27     private Data data;
28     public DataConsumer(Data data) {
29         this.data=data;
30     }
31     @Override
32     public void run() {
33         for(int x=0;x<50;x++) {
34             this.data.get();
35         }
36     } 
37 }
38 class Data{//负责数据保存
39     private String title;
40     private String note;
41     //flag=true 表示允许生产不允许消费者取走
42     //flag=false 表示生产完毕允许消费者取走不允许生产
43     private boolean flag=false;
44     public synchronized void get() {
45         if(this.flag==false) {//已经生产了,所以不允许重复生产
46             try {
47                 super.wait();
48             } catch (InterruptedException e1) {
49                 // TODO Auto-generated catch block
50                 e1.printStackTrace();
51             }//等待执行 
52         }
53         try {
54             Thread.sleep(50);
55         } catch (InterruptedException e) {
56             // TODO Auto-generated catch block
57             e.printStackTrace();
58         }
59         System.out.println(this.title+"="+this.note);
60         this.flag=false;//表示生产过了。不允许再生产了
61         super.notify();//唤醒等待线程
62     }
63     public synchronized void set(String title,String note) {
64         if(this.flag==true) {//现在不允许取走
65             try {
66                 super.wait();
67             } catch (InterruptedException e) {
68                 // TODO Auto-generated catch block
69                 e.printStackTrace();
70             }
71         }
72         this.title=title;
73         try {
74             Thread.sleep(100);
75         } catch (InterruptedException e) {
76             // TODO Auto-generated catch block
77             e.printStackTrace();
78         }
79         this.note=note;
80         this.flag=true;//继续生产
81         super.notify();
82     }
83 }
84  

面试题:请解释sleep()与wait()的区别

  sleep()是Thread类的方法到了一定的时间后该休眠自动唤醒

  wait()是Object类中的方法,要想唤醒必须使用notify(),notifyAll()

猜你喜欢

转载自www.cnblogs.com/Tony98/p/10491952.html
今日推荐