【多线程】_线程操作案例——生产者和消费者笔记

来源:互联网 发布:数控铣床加工中心编程 编辑:程序博客网 时间:2024/06/04 19:02
 

【多线程】_线程操作案例——生产者和消费者笔记

分类: Java
实例要求:在线程操作中有一个经典的案例程序——生产者和消费者问题,生产者不断生产,消费者不断取走生产者生产的产品。

既然是信息,所以就可以定义一个信息的表示类,生产者和消费者都同时占有这个信息类的引用,那么就可以将生产者和消费者两个线程通过信息类联合在一起。

[java] view plaincopyprint?
  1. class Info{//定义信息类  
  2.     private String name = "牛儿吃草";  
  3.     private String content = "Java 讲师";      
  4.     public void setName(String name){  
  5.         this.name = name;  
  6.     }  
  7.     public void setContent(String content){  
  8.         this.content = content;  
  9.     }  
  10.     public String getName(){  
  11.         return this.name;  
  12.     }  
  13.     public String getContent(){  
  14.         return this.content;  
  15.     }  
  16. }  
  17.   
  18. //建立生产者类,生产者实现多线程机制  
  19.   
  20. class Producer implements Runnable{  
  21.     private Info info = null;  
  22.     public Producer(Info info){  
  23.         this.info = info;  
  24.     }  
  25.     public void run(){  
  26.         boolean flag = false;  
  27.         for(int i=0;i<50;i++){  
  28.             if(flag){  
  29.                 this.info.setName("李兴华");  
  30.                 try{  
  31.                     Thread.sleep(90);  
  32.                 }catch(InterruptedException e){  
  33.                     e.printStackTrace();  
  34.                 }  
  35.                 this.info.setContent("JAVA讲师");  
  36.                 flag = false;  
  37.             }else{  
  38.                 this.info.setName("mldn");  
  39.                 try{  
  40.                     Thread.sleep(90);  
  41.                 }catch(InterruptedException e){  
  42.                     e.printStackTrace();  
  43.                 }  
  44.                 this.info.setContent("www.mldnjava.cn");//设置内容  
  45.                 flag = true;  
  46.             }  
  47.           
  48.         }  
  49.       
  50.     }  
  51. }  
  52.   
  53. //生产者生产50次信息,中间为了更好的发现问题,加入了延迟操作。  
  54. //实现消费者,消费者要不断的取出。  
  55.   
  56. class Consumer implements Runnable{  
  57.     private Info info = null;  
  58.     public Consumer(Info info){  
  59.         this.info = info;  
  60.     }  
  61.     public void run(){  
  62.         for(int i=0;i<50;i++){  
  63.             try{  
  64.                 Thread.sleep(90);  
  65.             }catch(InterruptedException e){  
  66.                 e.printStackTrack();  
  67.             }  
  68.             System.out.println(this.info.getName()+  
  69.                 "-->"+this.info.getContent()  
  70.             );  
  71.         }      
  72.     }  
  73. }  
  74.   
  75. //通过测试代码来发现程序的问题:  
  76.   
  77. public class ThreadCaseDemo01{  
  78.     public static void main(String args[]){  
  79.         Info info = new Info();  
  80.         Producer pro = new Producer(info);    //生产者  
  81.         Consumer con = new Consumer(info);  
  82.         new Thread(pro).start();  
  83.         new Thread(con).start();  
  84.     }  
  85.   
  86. }  



mldn-->JAVA讲师
mldn-->JAVA讲师
mldn-->JAVA讲师
mldn-->JAVA讲师
mldn-->JAVA讲师
李兴华-->www.mldnjava.cn
李兴华-->www.mldnjava.cn
李兴华-->www.mldnjava.cn
李兴华-->www.mldnjava.cn
mldn-->JAVA讲师
mldn-->JAVA讲师
李兴华-->www.mldnjava.cn


以上的代码将之前的两个问题全部暴露出来了。

之所以会出现内容不对应的情况,是因为中间加入了延迟操作,所以有可能产生不同步的问题,那么此时,可以使用同步解决设置内容的问题。

[java] view plaincopyprint?
  1. class Info{//定义信息类  
  2.     private String name = "牛儿吃草";  
  3.     private String content = "Java 讲师";      
  4.       
  5.     public synchronized void set(String name,String content){  
  6.         this.setName(name);    //设置名称  
  7.         try{  
  8.             Thread.sleep(300);  
  9.         }catch(InterruptedException e){  
  10.             e.printStackTrace();  
  11.         }  
  12.         this.setContent(content);  
  13.     }  
  14.     public synchronized void get(){  
  15.         try{  
  16.             Thread.sleep(300);  
  17.         }catch(InterruptedException e){  
  18.             e.printStackTrace();  
  19.         }  
  20.         System.out.println(this.getName()+"-->"+this.getContent());  
  21.     }  
  22.     public void setName(String name){  
  23.         this.name = name;  
  24.     }  
  25.     public void setContent(String content){  
  26.         this.content = content;  
  27.     }  
  28.     public String getName(){  
  29.         return this.name;  
  30.     }  
  31.     public String getContent(){  
  32.         return this.content;  
  33.     }  
  34. }  
  35. class Producer implements Runnable{  
  36.     private Info info = null;  
  37.     public Producer(Info info){  
  38.         this.info = info;  
  39.     }  
  40.     public void run(){  
  41.         boolean flag = false;  
  42.         for(int i=0;i<50;i++){  
  43.             if(flag){  
  44.                 this.info.set("李兴华","JAVA讲师");  
  45.                 flag = false;  
  46.             }else{  
  47.                 this.info.set("mldn","www.mldnjava.cn");  
  48.                 flag = true;  
  49.             }  
  50.         }  
  51.     }  
  52. }  
  53. class Consumer implements Runnable{  
  54.     private Info info = null;  
  55.     public Consumer(Info info){  
  56.         this.info = info;  
  57.     }  
  58.     public void run(){  
  59.         for(int i=0;i<50;i++){  
  60.             this.info.get();  
  61.         }      
  62.     }  
  63. }  
  64. public class ThreadCaseDemo02{  
  65.     public static void main(String args[]){  
  66.         Info info = new Info();  
  67.         Producer pro = new Producer(info);  
  68.         Consumer con = new Consumer(info);  
  69.         new Thread(pro).start();  
  70.         new Thread(con).start();  
  71.     }  
  72.   
  73.   
  74. }  



牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
mldn-->www.mldnjava.cn
mldn-->www.mldnjava.cn

以上的代码解决了数据完整性问题,但是依然存在了重复取的问题,既然有重复取,则肯定有重复设置问题。
并没有达到,设置一个取走一个的功能要求。

如果要想采用以上的一种机制,则必须依靠Object 类中的方法支持。

Object类对线程的支持——等待与唤醒

Object 类是所有类的父类,在此类中有以下几个方法是对线程操作有所支持的。

唤醒现有两个方法:notify,notifyAll

notify()方法唤醒第一个等待的线程执行
notifyAll()方法唤醒所有的等待线程执行

[java] view plaincopyprint?
  1. class Info{    // 定义信息类  
  2.     private String name = "李兴华";     // 定义name属性  
  3.     private String content = "JAVA讲师"  ;        // 定义content属性  
  4.     private boolean flag = false ;    // 设置标志位  
  5.     public synchronized void set(String name,String content){  
  6.         if(!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.         if(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 = false ;    // 定义标记位  
  61.         for(int i=0;i<50;i++){  
  62.             if(flag){  
  63.                 this.info.set("李兴华","JAVA讲师") ;    // 设置名称  
  64.                 flag = false ;  
  65.             }else{  
  66.                 this.info.set("mldn","www.mldnjava.cn") ;    // 设置名称  
  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<50;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.         new Thread(con).start() ;  
  90.     }  
  91. };  
0 0
原创粉丝点击