ITPub博客

首页 > Linux操作系统 > Linux操作系统 > java生产者消费者经典问题

java生产者消费者经典问题

原创 Linux操作系统 作者:hbm1985 时间:2012-11-20 14:34:13 0 删除 编辑
原文地址:http://eric-619.iteye.com/blog/693681
 
Java代码 复制代码 收藏代码
  1. /*@src  http://eric-619.iteye.com/blog/693681  
  2. * 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买  
  3. * 一、重点:  
  4. *    1、多个线程数据共享区域化思想!---源于多线程的近亲思想!!(类似于静态变量的改变)  
  5. *    (如栈内存和对内存,还有当做栈内存和堆内存,如数组和基本数据类型,只要是访问的同一个。)  
  6. *    2、生产者消费者  
  7. *      
  8. * 二、synchronized加锁:  
  9.  
  10. */  
  11.   
  12.   
  13. public class ProCon{ //主方法   
  14.   
  15. public static void main(String[] args){   
  16. SyncStack stack = new SyncStack();   
  17. Consumer p = new Consumer(stack);   
  18. Producer c = new Producer(stack);   
  19.   
  20.   
  21. new Thread(p).start();   
  22. new Thread(c).start();   
  23. }   
  24. }   
  25.   
  26. class Producer implements Runnable{   //生产者   
  27.     private SyncStack stack;   
  28.   
  29.     public Producer(SyncStack stack){   
  30.     this.stack = stack;   
  31.      }   
  32.   
  33.     public void run(){   
  34.     for (int i = 0; i < stack.pro().length; i++){   
  35.     String product = "产品"+i;   
  36.     stack.push(product);   
  37.     System.out.println("生产了: "+product);   
  38.     try{   
  39.      Thread.sleep(200);   
  40.      }catch(InterruptedException e)   
  41.       {   
  42.        e.printStackTrace();   
  43.      }   
  44.    }   
  45. }   
  46. }   
  47.   
  48. class Consumer implements Runnable{   //消费者   
  49.    private SyncStack stack;   
  50.   
  51.    public Consumer(SyncStack stack) {   
  52.    this.stack = stack;   
  53.     }   
  54.       
  55.    public void run(){   
  56.    for(int i = 0; i < stack.pro().length; i++){   
  57.     String product = stack.pop();   
  58.     System.out.println("消费了: "+product);   
  59.     try{   
  60.      Thread.sleep(1000);   
  61.    }catch(InterruptedException e){   
  62.      e.printStackTrace();   
  63.      }   
  64.     }   
  65.    }   
  66. }   
  67.   
  68. class SyncStack{   // 此类是(本质上:共同访问的)共享数据区域   
  69. private String[] str = new String[10];   
  70.     private int index;   
  71.        
  72.     public synchronized void push(String sst){ //供生产者调用   
  73.     if(index == sst.length()){   
  74.      try{   
  75.       wait();   
  76.      }catch(InterruptedException e){   
  77.        e.printStackTrace();   
  78.       }   
  79.     }   
  80.    this.notify(); //唤醒在此对象监视器上等待的单个线程   
  81.    str[index] = sst;   
  82.    index++;   
  83. }   
  84.   
  85.    public synchronized String pop(){   //供消费者调用   
  86.     if(index == 0){   
  87.      try{   
  88.       wait();   
  89.       }catch (InterruptedException e){   
  90.        e.printStackTrace();   
  91.       }   
  92.    }   
  93.     notify();   
  94.     index--;   
  95.     String product = str[index];   
  96.     return product;   
  97.    }   
  98.   
  99.     public String[] pro(){ //就是定义一个返回值为数组的方法,返回的是一个String[]引用   
  100.      return str;   //这是一个String[]引用   
  101.    }   
  102. }  
分享到:
评论
10 楼 somen 2012-07-29  
if (index == str.length() -1)

两个notify()的位置有问题,是不是应该先生产或者消费了再notify() ?
9 楼 ZZX19880809 2012-06-06  
命名太差!sst,str,楼主自己都搞不清了~~
8 楼 dreamhyz 2012-04-13  
LZ 代码还是存在问题的。。
把push 中的 if(index == sst.length())  改成 while(index==sst.length()) 
pop 中的也一样。。  
7 楼 337240552 2011-07-27  
public synchronized void push(String sst){
//满了
if(index == sst.length()){//这里应该是笔误吧,应该是表示已满,等待消费,应该是index == str.length; 个人认为是这样
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.notify();//唤醒在此对象监视器上等待的单个线程
str[index] = sst;
index++;
}
}
6 楼 lostyue 2011-07-13  
index == sst.length()
应该是
index == str.length;????

比较字符长度有什么意义?
5 楼 yzzlijun 2010-06-21  
有线程安全的原子queue,比一般的queue要慢。曾经测试过,原子integer和普通integer,性能上差别不是很大。
4 楼 beneo 2010-06-19  
那如果 str.length == inded == 0

岂不是两边都wait?
3 楼 gogole_09 2010-06-19  
banfry 写道
gogole_09 写道
eric_619 写道

Java代码 复制代码 收藏代码
  1. /*@src  http://eric-619.iteye.com/blog/693681  
  2. * 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买  
  3. * 一、重点:  
  4. *    1、多个线程数据共享区域化思想!---源于多线程的近亲思想!!(类似于静态变量的改变)  
  5. *    (如栈内存和对内存,还有当做栈内存和堆内存,如数组和基本数据类型,只要是访问的同一个。)  
  6. *    2、生产者消费者  
  7. *      
  8. * 二、synchronized加锁:  
  9.  
  10. */  
  11.   
  12.   
  13. public class ProCon{ //主方法   
  14.   
  15. public static void main(String[] args){   
  16. SyncStack stack = new SyncStack();   
  17. Consumer p = new Consumer(stack);   
  18. Producer c = new Producer(stack);   
  19.   
  20.   
  21. new Thread(p).start();   
  22. new Thread(c).start();   
  23. }   
  24. }   
  25.   
  26. class Producer implements Runnable{   //生产者   
  27.     private SyncStack stack;   
  28.   
  29.     public Producer(SyncStack stack){   
  30.     this.stack = stack;   
  31.      }   
  32.   
  33.     public void run(){   
  34.     for (int i = 0; i < stack.pro().length; i++){   
  35.     String product = "产品"+i;   
  36.     stack.push(product);   
  37.     System.out.println("生产了: "+product);   
  38.     try{   
  39.      Thread.sleep(200);   
  40.      }catch(InterruptedException e)   
  41.       {   
  42.        e.printStackTrace();   
  43.      }   
  44.    }   
  45. }   
  46. }   
  47.   
  48. class Consumer implements Runnable{   //消费者   
  49.    private SyncStack stack;   
  50.   
  51.    public Consumer(SyncStack stack) {   
  52.    this.stack = stack;   
  53.     }   
  54.       
  55.    public void run(){   
  56.    for(int i = 0; i < stack.pro().length; i++){   
  57.     String product = stack.pop();   
  58.     System.out.println("消费了: "+product);   
  59.     try{   
  60.      Thread.sleep(1000);   
  61.    }catch(InterruptedException e){   
  62.      e.printStackTrace();   
  63.      }   
  64.     }   
  65.    }   
  66. }   
  67.   
  68. class SyncStack{   // 此类是(本质上:共同访问的)共享数据区域   
  69. private String[] str = new String[10];   
  70.     private int index;   
  71.        
  72.     public synchronized void push(String sst){ //供生产者调用   
  73.     if(index == sst.length()){   
  74.      try{   
  75.       wait();   
  76.      }catch(InterruptedException e){   
  77.        e.printStackTrace();   
  78.       }   
  79.     }   
  80.    this.notify(); //唤醒在此对象监视器上等待的单个线程   
  81.    str[index] = sst;   
  82.    index++;   
  83. }   
  84.   
  85.    public synchronized String pop(){   //供消费者调用   
  86.     if(index == 0){   
  87.      try{   
  88.       wait();   
  89.       }catch (InterruptedException e){   
  90.        e.printStackTrace();   
  91.       }   
  92.    }   
  93.     notify();   
  94.     index--;   
  95.     String product = str[index];   
  96.     return product;   
  97.    }   
  98.   
  99.     public String[] pro(){ //就是定义一个返回值为数组的方法,返回的是一个String[]引用   
  100.      return str;   //这是一个String[]引用   
  101.    }   
  102. }  


  作为原理分析来写的话,代码比较清晰了,另外,synchronize关键字带来的是弱并发,如果在正式项目中使用的话,并不建议自己写 生产者-消费者模式,  一种替代的办法是,尽量使用concurrent包里面的东西来作并发处理,  比如使用BlockingQueue来实现生产者与消费者模式。 用ConcurrentHashMap来实现缓存等等。
  PS: BlockingQueue 在Thinking in Java的第4版, 并发那章有例子,lz有兴趣可以看看,代码比这个会简洁不少。


gogole_09 ,  使用BlockingQueue是为了提高并发还是简化代码?

  在我个人看来,2个都有,
   1.无疑,它简化了消费者代码,它本身为阻塞队列,所以在队列空的时候,会被阻塞直到有可用数据出现。
   2.第2个优点,也就是可以提高并发性, 如果你尝试看一下BlockingQueue实现类的源代码,你会发现,它的实现内部将ReentrantLock与原子操作代替了synchronize,这有利于性能的提升.
2 楼 banfry 2010-06-19  
gogole_09 写道
eric_619 写道

Java代码 复制代码 收藏代码
  1. /*@src  http://eric-619.iteye.com/blog/693681  
  2. * 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买  
  3. * 一、重点:  
  4. *    1、多个线程数据共享区域化思想!---源于多线程的近亲思想!!(类似于静态变量的改变)  
  5. *    (如栈内存和对内存,还有当做栈内存和堆内存,如数组和基本数据类型,只要是访问的同一个。)  
  6. *    2、生产者消费者  
  7. *      
  8. * 二、synchronized加锁:  
  9.  
  10. */  
  11.   
  12.   
  13. public class ProCon{ //主方法   
  14.   
  15. public static void main(String[] args){   
  16. SyncStack stack = new SyncStack();   
  17. Consumer p = new Consumer(stack);   
  18. Producer c = new Producer(stack);   
  19.   
  20.   
  21. new Thread(p).start();   
  22. new Thread(c).start();   
  23. }   
  24. }   
  25.   
  26. class Producer implements Runnable{   //生产者   
  27.     private SyncStack stack;   
  28.   
  29.     public Producer(SyncStack stack){   
  30.     this.stack = stack;   
  31.      }   
  32.   
  33.     public void run(){   
  34.     for (int i = 0; i < stack.pro().length; i++){   
  35.     String product = "产品"+i;   
  36.     stack.push(product);   
  37.     System.out.println("生产了: "+product);   
  38.     try{   
  39.      Thread.sleep(200);   
  40.      }catch(InterruptedException e)   
  41.       {   
  42.        e.printStackTrace();   
  43.      }   
  44.    }   
  45. }   
  46. }   
  47.   
  48. class Consumer implements Runnable{   //消费者   
  49.    private SyncStack stack;   
  50.   
  51.    public Consumer(SyncStack stack) {   
  52.    this.stack = stack;   
  53.     }   
  54.       
  55.    public void run(){   
  56.    for(int i = 0; i < stack.pro().length; i++){   
  57.     String product = stack.pop();   
  58.     System.out.println("消费了: "+product);   
  59.     try{   
  60.      Thread.sleep(1000);   
  61.    }catch(InterruptedException e){   
  62.      e.printStackTrace();   
  63.      }   
  64.     }   
  65.    }   
  66. }   
  67.   
  68. class SyncStack{   // 此类是(本质上:共同访问的)共享数据区域   
  69. private String[] str = new String[10];   
  70.     private int index;   
  71.        
  72.     public synchronized void push(String sst){ //供生产者调用   
  73.     if(index == sst.length()){   
  74.      try{   
  75.       wait();   
  76.      }catch(InterruptedException e){   
  77.        e.printStackTrace();   
  78.       }   
  79.     }   
  80.    this.notify(); //唤醒在此对象监视器上等待的单个线程   
  81.    str[index] = sst;   
  82.    index++;   
  83. }   
  84.   
  85.    public synchronized String pop(){   //供消费者调用   
  86.     if(index == 0){   
  87.      try{   
  88.       wait();   
  89.       }catch (InterruptedException e){   
  90.        e.printStackTrace();   
  91.       }   
  92.    }   
  93.     notify();   
  94.     index--;   
  95.     String product = str[index];   
  96.     return product;   
  97.    }   
  98.   
  99.     public String[] pro(){ //就是定义一个返回值为数组的方法,返回的是一个String[]引用   
  100.      return str;   //这是一个String[]引用   
  101.    }   
  102. }  


  作为原理分析来写的话,代码比较清晰了,另外,synchronize关键字带来的是弱并发,如果在正式项目中使用的话,并不建议自己写 生产者-消费者模式,  一种替代的办法是,尽量使用concurrent包里面的东西来作并发处理,  比如使用BlockingQueue来实现生产者与消费者模式。 用ConcurrentHashMap来实现缓存等等。
  PS: BlockingQueue 在Thinking in Java的第4版, 并发那章有例子,lz有兴趣可以看看,代码比这个会简洁不少。


gogole_09 ,  使用BlockingQueue是为了提高并发还是简化代码?
1 楼 gogole_09 2010-06-19  
eric_619 写道

Java代码 复制代码 收藏代码
  1. /*@src  http://eric-619.iteye.com/blog/693681  
  2. * 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买  
  3. * 一、重点:  
  4. *    1、多个线程数据共享区域化思想!---源于多线程的近亲思想!!(类似于静态变量的改变)  
  5. *    (如栈内存和对内存,还有当做栈内存和堆内存,如数组和基本数据类型,只要是访问的同一个。)  
  6. *    2、生产者消费者  
  7. *      
  8. * 二、synchronized加锁:  
  9.  
  10. */  
  11.   
  12.   
  13. public class ProCon{ //主方法   
  14.   
  15. public static void main(String[] args){   
  16. SyncStack stack = new SyncStack();   
  17. Consumer p = new Consumer(stack);   
  18. Producer c = new Producer(stack);   
  19.   
  20.   
  21. new Thread(p).start();   
  22. new Thread(c).start();   
  23. }   
  24. }   
  25.   
  26. class Producer implements Runnable{   //生产者   
  27.     private SyncStack stack;   
  28.   
  29.     public Producer(SyncStack stack){   
  30.     this.stack = stack;   
  31.      }   
  32.   
  33.     public void run(){   
  34.     for (int i = 0; i < stack.pro().length; i++){   
  35.     String product = "产品"+i;   
  36.     stack.push(product);   
  37.     System.out.println("生产了: "+product);   
  38.     try{   
  39.      Thread.sleep(200);   
  40.      }catch(InterruptedException e)   
  41.       {   
  42.        e.printStackTrace();   
  43.      }   
  44.    }   
  45. }   
  46. }   
  47.   
  48. class Consumer implements Runnable{   //消费者   
  49.    private SyncStack stack;   
  50.   
  51.    public Consumer(SyncStack stack) {   
  52.    this.stack = stack;   
  53.     }   
  54.       
  55.    public void run(){   
  56.    for(int i = 0; i < stack.pro().length; i++){   
  57.     String product = stack.pop();   
  58.     System.out.println("消费了: "+product);   
  59.     try{   
  60.      Thread.sleep(1000);   
  61.    }catch(InterruptedException e){   
  62.      e.printStackTrace();   
  63.      }   
  64.     }   
  65.    }   
  66. }   
  67.   
  68. class SyncStack{   // 此类是(本质上:共同访问的)共享数据区域   
  69. private String[] str = new String[10];   
  70.     private int index;   
  71.        
  72.     public synchronized void push(String sst){ //供生产者调用   
  73.     if(index == sst.length()){   
  74.      try{   
  75.       wait();   
  76.      }catch(InterruptedException e){   
  77.        e.printStackTrace();   
  78.       }   
  79.     }   
  80.    this.notify(); //唤醒在此对象监视器上等待的单个线程   
  81.    str[index] = sst;   
  82.    index++;   
  83. }   
  84.   
  85.    public synchronized String pop(){   //供消费者调用   
  86.     if(index == 0){   
  87.      try{   
  88.       wait();   
  89.       }catch (InterruptedException e){   
  90.        e.printStackTrace();   
  91.       }   
  92.    }   
  93.     notify();   
  94.     index--;   
  95.     String product = str[index];   
  96.     return product;   
  97.    }   
  98.   
  99.     public String[] pro(){ //就是定义一个返回值为数组的方法,返回的是一个String[]引用   
  100.      return str;   //这是一个String[]引用   
  101.    }   
  102. }  


  作为原理分析来写的话,代码比较清晰了,另外,synchronize关键字带来的是弱并发,如果在正式项目中使用的话,并不建议自己写 生产者-消费者模式,  一种替代的办法是,尽量使用concurrent包里面的东西来作并发处理,  比如使用BlockingQueue来实现生产者与消费者模式。 用ConcurrentHashMap来实现缓存等等。
  PS: BlockingQueue 在Thinking in Java的第4版, 并发那章有例子,lz有兴趣可以看看,代码比这个会简洁不少。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/18760228/viewspace-749563/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2011-02-22

最新文章