public class TestProducerConsumer {
public static void main(String[] args) {
// TODO Auto-generated method stub

SyncStack ss=new SyncStack();
producer p=new producer(ss);
customer c=new customer(ss);
new Thread(p).start();
new Thread(c).start();
}
}class WoTou{
int id=0;
WoTou(int id){
this.id=id;
}
public String toString(){
return "WoTou"+id;
}
}class SyncStack{
int index=0;
WoTou [] ArrWT=new WoTou[6];
public synchronized void push(WoTou wt){
if(index>=ArrWT.length){
try{
System.out.println("满了,等待消费");
wait();
}catch(InterruptedException e){
e.printStackTrace();
}

}
notify();
ArrWT[index]=wt;
index++;
}

public synchronized WoTou pop(){
if(index==0){
try{
System.out.println("没WoTou了,等待生产");
wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
notify();
index--;
return ArrWT[index];

}
}class producer implements Runnable{
SyncStack ss=null;
producer(SyncStack ss){
this.ss=ss;
}

public void run(){
for (int i =0;i<20;i++){
WoTou wt=new WoTou(i);
ss.push(wt);
System.out.println("生产了:"+wt);
try{
Thread.sleep(200);
}catch(Exception e){
e.printStackTrace();
}
}
}

}class customer implements Runnable{
SyncStack ss=null;
customer(SyncStack ss){
this.ss=ss;
}

public void run(){
for(int i=0;i<20;i++){
WoTou wt=ss.pop();
System.out.println("消费了:        "+wt);
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
}

}

}
得出的结果为:
生产了:WoTou0
消费了:        WoTou0
生产了:WoTou1
生产了:WoTou2
生产了:WoTou3
生产了:WoTou4
消费了:        WoTou4
生产了:WoTou5
生产了:WoTou6
生产了:WoTou7
满了,等待消费
生产了:WoTou8
消费了:        WoTou7
满了,等待消费
消费了:        WoTou8
生产了:WoTou9
满了,等待消费
生产了:WoTou10
消费了:        WoTou9
满了,等待消费
生产了:WoTou11
消费了:        WoTou10
满了,等待消费
消费了:        WoTou11
生产了:WoTou12
满了,等待消费
生产了:WoTou13
消费了:        WoTou12
满了,等待消费
生产了:WoTou14
消费了:        WoTou13
满了,等待消费
消费了:        WoTou14
生产了:WoTou15
满了,等待消费
生产了:WoTou16
消费了:        WoTou15
满了,等待消费
生产了:WoTou17
消费了:        WoTou16
满了,等待消费
消费了:        WoTou17
生产了:WoTou18
满了,等待消费
生产了:WoTou19
消费了:        WoTou18
消费了:        WoTou19
消费了:        WoTou6
消费了:        WoTou5
消费了:        WoTou3
消费了:        WoTou2
消费了:        WoTou1
提示满了,怎么还在生产呢?难道是wait()没起作用?请教高手。

解决方案 »

  1.   

    生产和消费的打印语句放到生产和消费的方法里public synchronized void push(WoTou wt) {
            if (index >= ArrWT.length) {
                try {
                    System.out.println("满了,等待消费");
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            ArrWT[index++] = wt;
            System.out.println("生产了:" + wt);
            notify();
        }    public synchronized WoTou pop() {
            if (index == 0) {
                try {
                    System.out.println("没WoTou了,等待生产");
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("消费了:        " + ArrWT[--index]);
            notify();
            return ArrWT[index];
        }
      

  2.   

    生产和消费的打印语句放到生产和消费的方法里public synchronized void push(WoTou wt) {
            if (index >= ArrWT.length) {
                try {
                    System.out.println("满了,等待消费");
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            ArrWT[index++] = wt;
            System.out.println("生产了:" + wt);
            notify();
        }    public synchronized WoTou pop() {
            if (index == 0) {
                try {
                    System.out.println("没WoTou了,等待生产");
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("消费了:        " + ArrWT[--index]);
            notify();
            return ArrWT[index];
        }
      

  3.   

    楼主,你这个程序生产满了是因为在SyncStack类里,规定生产满6个,就认为满了,所以等待。
    等到消费了,它的数量就少于6个了。然后它就又生产。直到生产producer类里规定的数量(20)为止.
      

  4.   

    但是当它满了之后,应该是先要消费了, 可是为什么它又会生产?
    生产了:WoTou7 
    满了,等待消费 
    生产了:WoTou8 
    消费了:        WoTou7 
      

  5.   

    pop()方法中的
    notify(); 
    index--; 这可以导致去生产!
    return ArrWT[index]; 
    当执行完这三句代码后,退出了方法,就说明c释放了对象的锁:p线程已经醒来,就会和c线程抢占资源,
    此时customer中的
    System.out.println("消费了:        "+wt); 代码还没有执行。
    这个时候就要看p和c线程那个能抢到资源了。
    出现你这种情况是p抢占到了资源了,因为允许生产,所以就生产了。
    然后p生产满了,然后c线程接着执行它的代码,所以你会看到这样的情况。
    修改了一下lz的代码,lz好好揣摩一下!
    public class TestProducerConsumer {
    public static void main(String[] args) {
    SyncStack ss = new SyncStack();
    producer p = new producer(ss);
    customer c = new customer(ss);
    new Thread(p).start();
    new Thread(c).start();
    }
    }class WoTou {
    int id = 0; WoTou(int id) {
    this.id = id;
    } public String toString() {
    return "WoTou" + id;
    }
    }class SyncStack {
    int index = 0; WoTou[] ArrWT = new WoTou[6]; public synchronized void push(WoTou wt) {
    if (index >= ArrWT.length) {
    try {
    System.out.println("---------------满了,等待消费");
    wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    } }
    ArrWT[index] = wt;
    index++;
    notify();//执行完自己的代码才去唤醒别人,要不别人就会和你抢cpu资源。 } // 改变这无返回值
    public synchronized void pop() {
    if (index == 0) {
    try {
    System.out.println("没WoTou了,等待生产");
    wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    notify();//虽然我唤醒了那些等待的线程,但线程我还是持有对象的锁!!!
    index--;
    // return ArrWT[index];
    // 改变如下:
    System.out.println("消费了:        " + ArrWT[index]);
    }
    }class producer implements Runnable {
    SyncStack ss = null; producer(SyncStack ss) {
    this.ss = ss;
    } public void run() {
    for (int i = 0; i < 20; i++) {
    WoTou wt = new WoTou(i);
    ss.push(wt);
    System.out.println("生产了:" + wt);
    try {
    Thread.sleep(200);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }}class customer implements Runnable {
    SyncStack ss = null; customer(SyncStack ss) {
    this.ss = ss;
    } public void run() {
    for (int i = 0; i < 20; i++) {
    // WoTou wt=ss.pop();//锁定了对象
    //执行到下面这句,你已经没有对象的锁!!!
    // System.out.println("消费了: "+wt);
    // 改变如下:
    ss.pop();//锁定了对象
    try {
    Thread.sleep(1000);
    } catch (Exception e) {
    e.printStackTrace();
    }
    } }}关键还是持有对象的锁!!!
      

  6.   

    楼上分析的分析的非常正确,楼主的问题总结:
    1.为什么满了还生产  :输出语句应该放在方法锁内,事实上已经消费了一个,但是由于输出语句在外面所以少打印一个
    2.还有就是if (index >= ArrWT.length) {
       改为while(index >= ArrWT.length) ----避免出现异常时还能再次判断
      

  7.   

    我觉得是不是你的wait()不对?是不是要加上在哪个资源上wait()?然后在对应的资源上notify()才会管用吧?
      

  8.   

    下面是我实现的一个生产者消费者问题,
    LZ参考下:/**
     * 生产者消费者问题
     */
    package net.csdn.blog.johnston;/**
     * @author johnston678
     *
     * @version 2009-05-06
     */
    public class ProducerConsumer { /**
      * @param args
      */
     public static void main(String[] args) {  
      ProductBox pb = new ProductBox();
      Producer p = new Producer(pb);
      Consumer c = new Consumer(pb);
      
      Thread pThread = new Thread(p);
      Thread cThread = new Thread(c);
      pThread.setPriority(Thread.MAX_PRIORITY);
      
      pThread.start();
      cThread.start();
     }}/**
     * 产品对象
     * @author johsnton678
     */
    class Product {
     int id; public Product(int id) {
      super();
      this.id = id;
     }
     
     public String toString(){
      return "Product:" + id;
     }
    }/**
     * 产品盒对象
     * @author johnston678
     */
    class ProductBox { Product[] productbox = new Product[6];
     int index = 0;
     public ProductBox() {
      super();  
     }
     
     public synchronized void push(Product p) {
      while (index == productbox.length) {
       try {
        this.wait();
       } catch (InterruptedException e) {
        
        e.printStackTrace();
       }
      }
      this.notify();  
      productbox[index] = p;
      index ++;
     }
     
     public synchronized Product pop() {
      while (index == 0) {
       try {
        this.wait();
       } catch (InterruptedException e) {    e.printStackTrace();
       }
      }
      this.notify();
      index --;
      return productbox[index];
      
     }
    }/**
     * 生产者
     * @author johnston678
     */
    class Producer implements Runnable { ProductBox productbox = null;
     
     public Producer(ProductBox productbox) {
      super();
      this.productbox = productbox;
     } @Override
     public void run() {
      
      for (int i=0; i<10; i++) {
       Product p = new Product(i);
       productbox.push(p);
       System.out.println("produce:" + p);
       
       try {
        Thread.sleep((int)(Math.random() * 200));
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
      }
     }
     
    }/**
     * 消费者
     * @author johnston678
     */
    class Consumer implements Runnable { ProductBox productbox = null;
     
     public Consumer(ProductBox productbox) {
      super();
      this.productbox = productbox;
     } @Override
     public void run() {
      
      for (int i=0; i<10; i++) {
       Product p = productbox.pop();
       System.out.println("consume:" + p);
       
       try {
        Thread.sleep((int)(Math.random() * 1000));
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
      }
     }
    }
    运行结果:
    produce:Product:0
    consume:Product:0
    produce:Product:1
    produce:Product:2
    produce:Product:3
    produce:Product:4
    produce:Product:5
    produce:Product:6
    consume:Product:6
    produce:Product:7
    consume:Product:7
    produce:Product:8
    consume:Product:8
    produce:Product:9
    consume:Product:9
    consume:Product:5
    consume:Product:4
    consume:Product:3
    consume:Product:2
    consume:Product:1
      

  9.   

    使用线程池,非常的easy,记得使用容量有限的任务队列就可以。
      

  10.   

    生产者,消费者的模型,baidu下,很多的例子,这种我认为学java的人都应该会的
      

  11.   

    其实生产者与消费者就是为了让学线程的人理解用wait()和notify()来实现多线程的同步其实有更好理解的例子,我觉的如果写出来,就说明能用了就是建立两个线程,一个打印1,一个打印0,两个线程同时运作,就打印10101010101010.。
      

  12.   

    我来回一下,基本就是wait()和notifyAll()两个方法。
    思路是:一生产者一消费者一罐子
    重点是罐子:
    有两个同步方法取和存,取的时候发现没有可取就调用wait()阻塞(此时阻塞的是调用取方法的消费者线程)
    存的时候发现罐子中的东西已经足够多,就调用wait()阻塞(此时阻塞的是调用存方法的生产者线程)
    如果上述情况没有发生,则执行存和取,并在方法结束和return前调用notifyAll(),使所有阻塞线程重新转为竞争上岗状态。
    调用wait()和notifyAll()方法时必须在当前线程上,否则会抛出一个运行时异常。
    楼主的错误应该与线程无关,估计是判断环节出了漏子
      

  13.   

    weiluo12 
    已作出了分析,synchronized 用的this作为锁对象,同一时候也只有一个线程能拿到锁,wait(),notify()都不是长占锁操作,所以当你在pop()中notify()即叫醒了其它线程,
    那么当pop()运行完了,锁交出,push()运行的线程可能会抢到锁开始运行,那么在消费者里的System.out.println("消费了:        " + wt);就不会输出了......不过生产者消费者模式使用已在jdk1.5的时候已提供了很好的支持LinkedBlockingQueue
      

  14.   

    LZ,你在二个wait和二个notify前面加上this试试,调试了一下,应该没问题了。
      

  15.   

    输出应该放在push()和pop()中,加个栈满或空的判断,否则只要wait()一被唤醒,就会输出,将LZ代码稍作修改
    import java.util.ArrayList;
    import java.util.Random;public class ThreadExercise {
    public static void main(String[] args) {
    SyncStack ss = new SyncStack();
    producer p = new producer(ss);
    customer c = new customer(ss);
    new Thread(p).start();
    new Thread(c).start();
    }
    }class SyncStack {
    int index = 0;
    ArrayList[] al = new ArrayList[10]; public synchronized void push() {
    //如果生产池满,就阻塞push
    if (index >= al.length) {
    try {
    System.out.println("********生产池满,等待消费********");
    wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    } else {
    //生产池不满,物品个数加1
    index++;
    System.out.println("生产1个物品" + " 生产池中有 " + index + "个物品");
    }
    notifyAll();// 唤醒等待的线程!
    } public synchronized void pop() {
    //如果生产池空,就阻塞pop
    if (index == 0) {
    try {
    System.out.println("********生产池空,等待生产********");
    wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    } else {
    //生产池不空,物品个数减1
    index--;
    System.out.println("消费1个物品 " + " 生产池中有 " + index + "个物品");
    }
    notifyAll();// 唤醒等待的线程!
    }
    }class producer implements Runnable {
    SyncStack ss = null;
    Random random = new Random(); producer(SyncStack ss) {
    this.ss = ss;
    } public void run() {
    while (true) {
    ss.push();          //生产物品
    try {
    Thread.sleep(random.nextInt(2000));
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    }class customer implements Runnable {
    SyncStack ss = null;
    Random random = new Random(); customer(SyncStack ss) {
    this.ss = ss;
    } public void run() {
    while (true) {
    ss.pop();          //消费物品
    try {
    Thread.sleep(random.nextInt(2000));
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    }