我觉得线程最难的是同步,是吗?
public class ProducerConsumerDemo {
   public static void main(String[] args) {
      CubbyHole c = new CubbyHole();  //同步问题的产生,是不是正因为共享一个对象?
      Producer p1 = new Producer(c,1);
      Consumer c1 = new Consumer(c,1);
      p1.start();
      c1.start();
   }
}
class Producer extends Thread{
   private CubbyHole cubbyhole;
   private int number;
   public Producer(CubbyHole c,int number){
      cubbyhole = c;
      this.number = number;
   }
   public void run(){
      for(int i=0;i<10;i++){
         cubbyhole.put(i);
         System.out.println("Producer No."+this.number+"put: "+i);
         try{
            sleep((int)Math.random()*100);
         }catch(InterruptedException e){}
      }
   }
}
class Consumer extends Thread{
   private CubbyHole cubbyhole;
   private int number;
   public Consumer(CubbyHole c,int number){
      cubbyhole = c;
      this.number = number;
   }
   public void run(){
      int value = 0;
      for(int i=0;i<10;i++){
         value = cubbyhole.get();
         System.out.println("Consumber No." + this.number +"got: "+value);
      }
   }
}
class CubbyHole{
   private int contents;
   private boolean available = false;  //这个变量我觉得可有可无
   public synchronized int get(){
      while(available == false) {
         try{
            wait();
         }catch(InterruptedException e){}
      }
   available = false;
   notifyAll();             //我觉得与notify一样的。这个去掉也是能正确执行,晕    
   return contents;
   }
   public synchronized void put(int value){
      while(available == true){
         try{
            wait();
         }catch(InterruptedException e){}
      }
      contents = value;
      available = true;
      notify();
   }
}

解决方案 »

  1.   

    把 cubbyhole 看成一个仓库,只有一个格子的仓库
    available 代表格子中是否有物品
    上来时是false,说明没物品,这样生产者就可以put,但消费者get的话就会wait然后,生产者put之后,把格子标为满格,这样生成者就不能继续put了,然后唤醒所有等待cubbyhole的线程
    这时消费者被唤醒,进行消费,然后把格子标空,然后唤醒所有等待cubbyhole的线程,生产者就能继续生产
      

  2.   

    //同步问题的产生,是不是正因为共享一个对象?
    //我觉得与notify一样的。这个去掉也是能正确执行?
      

  3.   

     生产者消费者的问题,个人觉得可以去看看马士兵老师的视频,挺好理解的。
     同步问题是因为在整个执行过程中,大家都会不定时的使用到同一个对象里的东西。
     使用private boolean available = false; 这个变量,2楼说得挺明白的。
     notifyAll() 这个方法则是一定需要的。因为当你是几个线程同时运行的时候,会有可能随机出现仓库满致使生产者无法put而进入wait状态,或者是出现仓库空儿致使消费者听着消费无法get而进入wait状态。此时若没有notifyAll() 则会出现一个永久等待,使得程序无法继续执行。( 然,你可以不使用notifyAll()而使用notify() )
      

  4.   

    private boolean available = false;  //这个变量我觉得可有可无
    如果没有这个变量,无论是生产者还是消费者在生产数据和取数据时都会发生等待,也就是会导致相互等待的问题,也就是出现死锁了。notifyAll();             //我觉得与notify一样的。这个去掉也是能正确执行,晕  你可以在Consumer的run方法中加个
    for(int i=0;i<10;i++){
      try{
    Thread.sleep(1000);
      } catch(Exception e) {}
    来看看效果,就会出现不同步的问题了。
      

  5.   

    对,同步的问题是因为对共享数据的操作导致的,你必须保证wait 和 notifyAll成对出现。
      

  6.   

    有个非常大的疑问:[java]
       public synchronized void put(int value){
          while(available == true){
             try{
                wait();
             }catch(InterruptedException e){}
          }
          contents = value;
          available = true;
          notify();  //这个notify会不会唤醒同一工程里其它了正在wait的线程,那不是乱套了吗?
       }[/java]
      

  7.   

    public synchronized void put 锁的是对象本身,就是"c"生产者和消费者争抢的就是"c"这个资源notify()也就是this.notify(),唤醒所有争抢自己的线程
    代码也可以这么写public void put(int value) {
    synchronized (this) {
    while (available == true) {
    try {
    wait();
    } catch (InterruptedException e) {
    }
    }
    contents = value;
    available = true;
    this.notify();
    }
    }
      

  8.   

    那个wait();其实是this.wait();
    等待this,也就是c这个资源notify(); 就是 this.notify()
    释放c这个资源
      

  9.   

    说错了,不是释放,是唤醒所有wait c的线程
      

  10.   

     CubbyHole c = new CubbyHole();  //同步问题的产生,是不是正因为共享一个对象? 
    对的。如果每个线程使用独立的CubbyHole ,那就不是多线程了。多线程实际就是说的多个线程同时对一个资源来读写。private boolean available = false;  //这个变量我觉得可有可无
    这个变量其实就是一个标识位,用来标识生产线程是否可以继续生产,消费线程是否可以继续消费。如果没这个变量的话,就没法判断生产线程什么时候继续生产,消费线程什么时候可以继续消费notifyAll();             //我觉得与notify一样的。这个去掉也是能正确执行,晕    
    能正确执行是因为线程没有休眠足够长的时间,就像5L的哥们说的那样,你让生产者或者消费者休眠一下。或者让生产者休眠的时间大于消费者休眠的时间 ,或者让生产者休眠的时间小于消费者休眠的时间,这个时候注释notifyAll(); 后,程序就会挂起了。你注释的是get中的notifyAll();。你可以让生产线程生产的速度大于消费线程,也就是让生产者休眠的时间小于消费者休眠的时间。这样生产完成后,生产线程wait()。然后消费线程调用get后,不会notifyAll();。由于生产线程不会被唤醒,迟早会有消费完的一个时点,那个时候之后,两个线程都处于休眠了。程序就会挂起了
    notify();  //这个notify会不会唤醒同一工程里其它了正在wait的线程,那不是乱套了吗? 
    会的,全部唤醒只是说一起去竞争cpu的资源罢了 最终在一个cpu中执行的线程永远就只有一个
      

  11.   

    notify和notifyAll()虽然在效果上有时差不多,但对于许多人员来说,还是建议用notifyAll,当你确切知道waitset中只有一个线程而且这个线程就是你要的那个线程时,notify和notifyAll()效果是一样的,因为只有一个嘛。
    但是由于在waitset中如果有多个线程时,还会存在竞争机制,不一定会notify到你要的那个线程,采用notifyAll会让处于wait的所有线程一块重新竞争,这也就是while (available == true)这为什么要用while而不用if的原因了,因为有可能自己的wait的线程是由于被的原因被别的线程notify.