以下这段代码来自某教程
对执行结果困惑,请求高手解释一下class Test extends Thread
{
    public static void main(String[] args) //throws Exception
    {
        Queue q=new Queue();
        Producer p=new Producer(q);
        Consumer c=new Consumer(q);
        p.start();
        c.start();
    }
}
class Producer extends Thread
{
    Queue q;
    Producer(Queue q)
    {
        this.q=q;
    }
    public void run()
    {
        for(int i=0;i<10;i++)
        {
            q.put(i);
            System.out.println("producer  put  "+i);
        }
    }
}
class Consumer extends Thread
{
    Queue q;
    Consumer(Queue q)
    {
        this.q=q;
    }
    public void run()
    {
        for(int j=0;j<10;j++)
            System.out.println("consumer  get  "+q.get());
    }
}
class Queue
{
    int i;
    boolean b=false;
    public synchronized void put(int i)
    {
        if(!b)
        {   
            //System.out.println("producer  put  "+i);
            this.i=i;
            b=true;
            notify();
        }
        try
        {
            wait();
        }
        catch(Exception e){}
    }
    public synchronized int get()
    {
        if(!b)
        {
            try
        {
            wait();
        }
        catch(Exception e){}
        }
        b=false;
        notify();
        return i;
    }
}
我试了将Producer和Consumer类run()中的循环次数从3次一直改到10次
得到好几种打印顺序,想弄明白结果不一样的原因是什么    

解决方案 »

  1.   

    多线程中的生产者消费者问题。生产者和消费者共享一块缓冲区Queue。生产者生产数据到缓冲区。消费者从缓冲区中取数据。当缓冲区满时,生产者睡眠,不能向缓冲区放数据。当缓冲区空时,消费者睡眠,不能从缓冲区取数据。
      

  2.   

    eclipse中的运行结果如下:
    producer put 0
    consumer get 0
    producer put 1
    consumer get 1
    producer put 2
    consumer get 2
    producer put 3
    consumer get 3
    consumer get 4
    producer put 4
    consumer get 5
    producer put 5
    consumer get 6
    producer put 6
    consumer get 7
    producer put 7
    consumer get 8
    producer put 8
    producer put 9
    consumer get 9不明白的地方是,
    第1行为什么不是打印get 0(p线程执行第一次循环时,当它被wait时,打印语句应该还未执行,这时c线程启动)
    get3和get4接连打印出来,从get4开始变成get-put对
    一直到put8和put9,又变回put-get对
      

  3.   

    对于第一行为什么是put 0 这一问题,请运行如下代码实验。
    把c线程中("consumer get "+q.get());
    改为cc=q.get();Thread.sleep(10000);("consumer get "+cc);
    就不难发现该问题:执行q.get()时,系统可能发生还未来得及执行消费者线程的打印语句(("consumer get "+q.get());)呢,生产者线程就收到notify指令被放开,去执行System.out.println("producer put "+i);自然会出现先put 0再get 0的现象。对于顺序不一致的问题,这也是肯定的,你的wait()和notify()及互斥信号量b针对的仅仅是c线程和p线程中的queue线程而非c和p线程本生,c,p线程中的打印语句自然不受wait()和notify()及互斥信号量b的控制,所以尽管c,p线程中的queue线程得到了控制,但c,p线程中的打印语句是并发的,出现的顺序自然也就是随机的。
    若要做到对c,p线程的控制,wait()和notify()需要在c,p线程内部设置,而不是其它的第3个线程。class Test extends Thread
    {
      public static void main(String[] args) //throws Exception
      {
      Queue q=new Queue();
      Producer p=new Producer(q);
      Consumer c=new Consumer(q);
      p.start();
      c.start();
      }
    }
    class Producer extends Thread
    {
      Queue q;
      Producer(Queue q)
      {
      this.q=q;
      }
      public void run()
      {
      for(int i=0;i<1;i++)
      {
      q.put(i);
      System.out.println("producer put "+i);
      }
      }
    }
    class Consumer extends Thread
    {
      Queue q;
      int cc;
      Consumer(Queue q)
      {
      this.q=q;
      }
      public void run()
      {
      for(int j=0;j<1;j++)
          try
          {
              cc=q.get();
              Thread.sleep(1000);
          }
              catch(Exception e ){}
      System.out.println("consumer get "+cc);
      }
    }
    class Queue
    {
      int i;
      boolean b=false;
      public synchronized void put(int i)
      {
      if(!b)
      {   
      //System.out.println("producer put "+i);
      this.i=i;
      b=true;
      notify();
      }
      try
      {
      wait();
      }
      catch(Exception e){}
      }
      public synchronized int get()
      {
      if(!b)
      {
      try
      {
      wait();
      }
      catch(Exception e){}
      }
      b=false;
      notify();
      return i;
      }
    }
      

  4.   

    wait()允许我们将线程置入"睡眠"状态,同时又"积极"地等待条件发生改变.而且只有在一个notify()或notifyAll()发生变化的时候,线程才会被唤醒,并检查条件是否有变
      

  5.   

    wait notify nofityAll必须在sychronized块里调用