• 生产者—消费者模型


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

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

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

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

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

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

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

     详细的实现代码如下:

     1 class Info{ // 定义信息类  
     2     private String name = "name";//定义name属性,为了与下面set的name属性区别开  
     3     private String content = "content" ;// 定义content属性,为了与下面set的content属性区别开  
     4     private boolean flag = true ;   // 设置标志位,初始时先生产  
     5     public synchronized void set(String name,String content){  
     6         while(!flag){  
     7             try{  
     8                 super.wait() ;  
     9             }catch(InterruptedException e){  
    10                 e.printStackTrace() ;  
    11             }  
    12         }  
    13         this.setName(name) ;    // 设置名称  
    14         try{  
    15             Thread.sleep(300) ;  
    16         }catch(InterruptedException e){  
    17             e.printStackTrace() ;  
    18         }  
    19         this.setContent(content) ;  // 设置内容  
    20         flag  = false ; // 改变标志位,表示可以取走  
    21         super.notify();  
    22     }  
    23     public synchronized void get(){  
    24         while(flag){  
    25             try{  
    26                 super.wait() ;  
    27             }catch(InterruptedException e){  
    28                 e.printStackTrace() ;  
    29             }  
    30         }  
    31         try{  
    32             Thread.sleep(300) ;  
    33         }catch(InterruptedException e){  
    34             e.printStackTrace() ;  
    35         }  
    36         System.out.println(this.getName() +   
    37             " --> " + this.getContent()) ;  
    38         flag  = true ;  // 改变标志位,表示可以生产  
    39         super.notify();  
    40     }  
    41     public void setName(String name){  
    42         this.name = name ;  
    43     }  
    44     public void setContent(String content){  
    45         this.content = content ;  
    46     }  
    47     public String getName(){  
    48         return this.name ;  
    49     }  
    50     public String getContent(){  
    51         return this.content ;  
    52     }  
    53 }  
    54 class Producer implements Runnable{ // 通过Runnable实现多线程  
    55     private Info info = null ;      // 保存Info引用  
    56     public Producer(Info info){  
    57         this.info = info ;  
    58     }  
    59     public void run(){  
    60         boolean flag = true ;   // 定义标记位  
    61         for(int i=0;i<10;i++){  
    62             if(flag){  
    63                 this.info.set("姓名--1","内容--1") ;    // 设置名称  
    64                 flag = false ;  
    65             }else{  
    66                 this.info.set("姓名--2","内容--2") ;    // 设置名称  
    67                 flag = true ;  
    68             }  
    69         }  
    70     }  
    71 }  
    72 class Consumer implements Runnable{  
    73     private Info info = null ;  
    74     public Consumer(Info info){  
    75         this.info = info ;  
    76     }  
    77     public void run(){  
    78         for(int i=0;i<10;i++){  
    79             this.info.get() ;  
    80         }  
    81     }  
    82 }  
    83 public class ThreadCaseDemo03{  
    84     public static void main(String args[]){  
    85         Info info = new Info(); // 实例化Info对象  
    86         Producer pro = new Producer(info) ; // 生产者  
    87         Consumer con = new Consumer(info) ; // 消费者  
    88         new Thread(pro).start() ;  
    89         //启动了生产者线程后,再启动消费者线程  
    90         try{  
    91             Thread.sleep(500) ;  
    92         }catch(InterruptedException e){  
    93             e.printStackTrace() ;  
    94         }  
    95   
    96         new Thread(con).start() ;  
    97     }  
    98 }  

    执行结果如下:

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

  • 相关阅读:
    晨读,难道只是为了完成任务而读的吗?
    集合还有这么优雅的运算法?
    Java中的TreeSet集合会自动将元素升序排序
    CSS3的几个变形案例……
    “老师,请您多关注一下我吧!!!”
    jsp中使用cookie时报错……
    为什么要有周考?周考是用来干什么的?
    今天,我们就来抽个奖!
    今天 ,给大家变个魔术!!!
    Google Maps Api 多坐标分类标记,在地图上显示海量坐标,并分组显示。
  • 原文地址:https://www.cnblogs.com/lt132024/p/6442904.html
Copyright © 2020-2023  润新知