一下是马士兵老师的源代码,为什么连续运行几次后有时会出现没生产就开始消费的情况public class ProducerConsumer {
 public static void main(String[] args) {
  SyncStack ss = new SyncStack();
  Producer p = new Producer(ss);
  Consumer c = new Consumer(ss);
  new Thread(p).start();
  new Thread(c).start();
 }
}class WoTou {
 int id; 
 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) {
  while(index == arrWT.length) {
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  this.notifyAll();  
  arrWT[index] = wt;
  index ++;
 }
 
 public synchronized WoTou pop() {
  while(index == 0) {
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  this.notifyAll();
  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((int)(Math.random() * 200));
   } catch (InterruptedException e) {
    e.printStackTrace();
   }   
  }
 }
}class Consumer implements Runnable {
 SyncStack ss = null;
 Consumer(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((int)(Math.random() * 1000));
   } catch (InterruptedException e) {
    e.printStackTrace();
   }   
  }
 }

解决方案 »

  1.   

    一开始不信~~
    跑着跑着果然出现了问题出现的原因:
    其实是错觉。
    打印语句的位置不对
    打印语句是在执行完之后,在外部打印
    此时线程已经结束一个动作了例如:
    生产线程跑得慢了点,还没出来到外面打印:生产了 ,就已经notifyAll消费线程得到notifyAll通知,跑得快了点,就先出来打印:消费了这时候生产线程出来打印生产了修改方法:修改印位置
    生产方法push
               arrWT[index] = wt;
        index ++;
      System.out.println("生产了:"+wt);
      this.notifyAll();   消费方法pop:
          index--;
      this.notifyAll();
      System.out.println("消费了:"+ arrWT[index]);
      return arrWT[index];
      

  2.   

    把sleep的时间搞小一点看到了还没生产0就消费0了~~其实你可以随便假设某个时刻CPU切换,其实已经生产了,只不过在打印之前CPU切换了,然后pop,打印消费然后切换回来才打印生产了可以把“生产了”和“消费了”放到同步方法中
      

  3.   


    在这个程序中同步方法是哪个呢,synchronized是实现互斥访问吗,请指教,,谢谢。学习了好多