前言
消费者生产者模式是java中多线程的典型模式,它牵涉到java中多个线程交互的一些方式。下面根据一些典型的实现来说明;
一、方式1
该方式源码出处为:http://eric-619.iteye.com/blog/693681
(有一篇讲解多线程的非常有名的博客,建议初学多线程的朋友多关注一下,总结网址为:http://lavasoft.blog.51cto.com/62575/27069,顺便感谢一下这些大牛们为吾等小白扫盲!)
生产者-消费者模型准确说应该是“生产者-消费者-仓储”模型,离开了仓储,生产者消费者模型就显得没有说服力了。
对于此模型,应该明确一下几点:
1、生产者仅仅在仓储未满时候生产,仓满则停止生产。
2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。
3、当消费者发现仓储没产品可消费时候会通知生产者生产。
4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费
此模型将要结合java.lang.Object的wait与notify、notifyAll方法来实现以上的需求。这是非常重要的。
生产者和消费者通过共享内存的方式进行通信;它们共享的内存是:SyncStack对象;生产者通过SyncStack的同步方法pop向其中添加对象;消费者通过SyncStack的同步方法pop方法在SyncStack对象中获取对象;这是对象间共享内存(或共享数据区域)的方式进行的通信。
关键点详解:
其中的关键是共享内存区域中的两个同步方法,及同步方法中wait()方法的调用;同步保证了对象只能被一个线程占用,wait保证了当线程在等待的过程中释放自己的锁,使得其它对象有机会获得对象的锁;
缺点:
在多个线程进行操作时(有较多生产者和消费者时),使用notifyAll方法会造成不必要进行唤醒的方法进行线程的调度,从而导致不必要的时间花销;
比如一个消费者线程调用了notifyAll(),则会唤醒其它消费者,但是其本意是唤醒生产者来制造物品;由此可见,该方法并没有进行定点的通知。
/* * 生产者消费者问题其含义就是先生产出了产品,才能拉出去让消费者购买 * 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[]引用 } }