首页 > Linux操作系统 > Linux操作系统 > java生产者消费者经典问题
/*@src http://eric-619.iteye.com/blog/693681
* 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买
* 一、重点:
* 1、多个线程数据共享区域化思想!---源于多线程的近亲思想!!(类似于静态变量的改变)
* (如栈内存和对内存,还有当做栈内存和堆内存,如数组和基本数据类型,只要是访问的同一个。)
* 2、生产者消费者
*
* 二、synchronized加锁:
*
*/
public class ProCon{ //主方法
public static void main(String[] args){
SyncStack stack = new SyncStack();
Consumer p = new Consumer(stack);
Producer c = new Producer(stack);
new Thread(p).start();
new Thread(c).start();
}
}
class Producer implements Runnable{ //生产者
private SyncStack stack;
public Producer(SyncStack stack){
this.stack = stack;
}
public void run(){
for (int i = 0; i < stack.pro().length; i++){
String product = "产品"+i;
stack.push(product);
System.out.println("生产了: "+product);
try{
Thread.sleep(200);
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{ //消费者
private SyncStack stack;
public Consumer(SyncStack stack) {
this.stack = stack;
}
public void run(){
for(int i = 0; i < stack.pro().length; i++){
String product = stack.pop();
System.out.println("消费了: "+product);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
class SyncStack{ // 此类是(本质上:共同访问的)共享数据区域
private String[] str = new String[10];
private int index;
public synchronized void push(String sst){ //供生产者调用
if(index == sst.length()){
try{
wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.notify(); //唤醒在此对象监视器上等待的单个线程
str[index] = sst;
index++;
}
public synchronized String pop(){ //供消费者调用
if(index == 0){
try{
wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
notify();
index--;
String product = str[index];
return product;
}
public String[] pro(){ //就是定义一个返回值为数组的方法,返回的是一个String[]引用
return str; //这是一个String[]引用
}
}
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/18760228/viewspace-749563/ ,如需转载,请注明出处,否则将追究法律责任。
两个notify()的位置有问题,是不是应该先生产或者消费了再notify() ?
把push 中的 if(index == sst.length()) 改成 while(index==sst.length())
pop 中的也一样。。
//满了
if(index == sst.length()){//这里应该是笔误吧,应该是表示已满,等待消费,应该是index == str.length; 个人认为是这样
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.notify();//唤醒在此对象监视器上等待的单个线程
str[index] = sst;
index++;
}
}
应该是
index == str.length;????
比较字符长度有什么意义?
岂不是两边都wait?
/*@src http://eric-619.iteye.com/blog/693681 * 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买 * 一、重点: * 1、多个线程数据共享区域化思想!---源于多线程的近亲思想!!(类似于静态变量的改变) * (如栈内存和对内存,还有当做栈内存和堆内存,如数组和基本数据类型,只要是访问的同一个。) * 2、生产者消费者 * * 二、synchronized加锁: * */ public class ProCon{ //主方法 public static void main(String[] args){ SyncStack stack = new SyncStack(); Consumer p = new Consumer(stack); Producer c = new Producer(stack); new Thread(p).start(); new Thread(c).start(); } } class Producer implements Runnable{ //生产者 private SyncStack stack; public Producer(SyncStack stack){ this.stack = stack; } public void run(){ for (int i = 0; i < stack.pro().length; i++){ String product = "产品"+i; stack.push(product); System.out.println("生产了: "+product); try{ Thread.sleep(200); }catch(InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable{ //消费者 private SyncStack stack; public Consumer(SyncStack stack) { this.stack = stack; } public void run(){ for(int i = 0; i < stack.pro().length; i++){ String product = stack.pop(); System.out.println("消费了: "+product); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } } class SyncStack{ // 此类是(本质上:共同访问的)共享数据区域 private String[] str = new String[10]; private int index; public synchronized void push(String sst){ //供生产者调用 if(index == sst.length()){ try{ wait(); }catch(InterruptedException e){ e.printStackTrace(); } } this.notify(); //唤醒在此对象监视器上等待的单个线程 str[index] = sst; index++; } public synchronized String pop(){ //供消费者调用 if(index == 0){ try{ wait(); }catch (InterruptedException e){ e.printStackTrace(); } } notify(); index--; String product = str[index]; return product; } public String[] pro(){ //就是定义一个返回值为数组的方法,返回的是一个String[]引用 return str; //这是一个String[]引用 } }作为原理分析来写的话,代码比较清晰了,另外,synchronize关键字带来的是弱并发,如果在正式项目中使用的话,并不建议自己写 生产者-消费者模式, 一种替代的办法是,尽量使用concurrent包里面的东西来作并发处理, 比如使用BlockingQueue来实现生产者与消费者模式。 用ConcurrentHashMap来实现缓存等等。
PS: BlockingQueue 在Thinking in Java的第4版, 并发那章有例子,lz有兴趣可以看看,代码比这个会简洁不少。
gogole_09 , 使用BlockingQueue是为了提高并发还是简化代码?
在我个人看来,2个都有,
1.无疑,它简化了消费者代码,它本身为阻塞队列,所以在队列空的时候,会被阻塞直到有可用数据出现。
2.第2个优点,也就是可以提高并发性, 如果你尝试看一下BlockingQueue实现类的源代码,你会发现,它的实现内部将ReentrantLock与原子操作代替了synchronize,这有利于性能的提升.
/*@src http://eric-619.iteye.com/blog/693681 * 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买 * 一、重点: * 1、多个线程数据共享区域化思想!---源于多线程的近亲思想!!(类似于静态变量的改变) * (如栈内存和对内存,还有当做栈内存和堆内存,如数组和基本数据类型,只要是访问的同一个。) * 2、生产者消费者 * * 二、synchronized加锁: * */ public class ProCon{ //主方法 public static void main(String[] args){ SyncStack stack = new SyncStack(); Consumer p = new Consumer(stack); Producer c = new Producer(stack); new Thread(p).start(); new Thread(c).start(); } } class Producer implements Runnable{ //生产者 private SyncStack stack; public Producer(SyncStack stack){ this.stack = stack; } public void run(){ for (int i = 0; i < stack.pro().length; i++){ String product = "产品"+i; stack.push(product); System.out.println("生产了: "+product); try{ Thread.sleep(200); }catch(InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable{ //消费者 private SyncStack stack; public Consumer(SyncStack stack) { this.stack = stack; } public void run(){ for(int i = 0; i < stack.pro().length; i++){ String product = stack.pop(); System.out.println("消费了: "+product); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } } class SyncStack{ // 此类是(本质上:共同访问的)共享数据区域 private String[] str = new String[10]; private int index; public synchronized void push(String sst){ //供生产者调用 if(index == sst.length()){ try{ wait(); }catch(InterruptedException e){ e.printStackTrace(); } } this.notify(); //唤醒在此对象监视器上等待的单个线程 str[index] = sst; index++; } public synchronized String pop(){ //供消费者调用 if(index == 0){ try{ wait(); }catch (InterruptedException e){ e.printStackTrace(); } } notify(); index--; String product = str[index]; return product; } public String[] pro(){ //就是定义一个返回值为数组的方法,返回的是一个String[]引用 return str; //这是一个String[]引用 } }作为原理分析来写的话,代码比较清晰了,另外,synchronize关键字带来的是弱并发,如果在正式项目中使用的话,并不建议自己写 生产者-消费者模式, 一种替代的办法是,尽量使用concurrent包里面的东西来作并发处理, 比如使用BlockingQueue来实现生产者与消费者模式。 用ConcurrentHashMap来实现缓存等等。
PS: BlockingQueue 在Thinking in Java的第4版, 并发那章有例子,lz有兴趣可以看看,代码比这个会简洁不少。
gogole_09 , 使用BlockingQueue是为了提高并发还是简化代码?
/*@src http://eric-619.iteye.com/blog/693681 * 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买 * 一、重点: * 1、多个线程数据共享区域化思想!---源于多线程的近亲思想!!(类似于静态变量的改变) * (如栈内存和对内存,还有当做栈内存和堆内存,如数组和基本数据类型,只要是访问的同一个。) * 2、生产者消费者 * * 二、synchronized加锁: * */ public class ProCon{ //主方法 public static void main(String[] args){ SyncStack stack = new SyncStack(); Consumer p = new Consumer(stack); Producer c = new Producer(stack); new Thread(p).start(); new Thread(c).start(); } } class Producer implements Runnable{ //生产者 private SyncStack stack; public Producer(SyncStack stack){ this.stack = stack; } public void run(){ for (int i = 0; i < stack.pro().length; i++){ String product = "产品"+i; stack.push(product); System.out.println("生产了: "+product); try{ Thread.sleep(200); }catch(InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable{ //消费者 private SyncStack stack; public Consumer(SyncStack stack) { this.stack = stack; } public void run(){ for(int i = 0; i < stack.pro().length; i++){ String product = stack.pop(); System.out.println("消费了: "+product); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } } class SyncStack{ // 此类是(本质上:共同访问的)共享数据区域 private String[] str = new String[10]; private int index; public synchronized void push(String sst){ //供生产者调用 if(index == sst.length()){ try{ wait(); }catch(InterruptedException e){ e.printStackTrace(); } } this.notify(); //唤醒在此对象监视器上等待的单个线程 str[index] = sst; index++; } public synchronized String pop(){ //供消费者调用 if(index == 0){ try{ wait(); }catch (InterruptedException e){ e.printStackTrace(); } } notify(); index--; String product = str[index]; return product; } public String[] pro(){ //就是定义一个返回值为数组的方法,返回的是一个String[]引用 return str; //这是一个String[]引用 } }作为原理分析来写的话,代码比较清晰了,另外,synchronize关键字带来的是弱并发,如果在正式项目中使用的话,并不建议自己写 生产者-消费者模式, 一种替代的办法是,尽量使用concurrent包里面的东西来作并发处理, 比如使用BlockingQueue来实现生产者与消费者模式。 用ConcurrentHashMap来实现缓存等等。
PS: BlockingQueue 在Thinking in Java的第4版, 并发那章有例子,lz有兴趣可以看看,代码比这个会简洁不少。