如何用JAVA来实现“生产者―消费者”问题

 

  生产者和消费者问题是从操作系统中的许多实际同步问题中抽象出来的具有代表性的问题。它反映了操作系统中典型的同步例子。

  生产者进程(进程由多个线程组成)生产信息,例如它可以是计算进程。消费者进程使用信息,它可以是输出打印进程。由于生产者和消费者彼此独立,且运行速度不确定,所以很可能出现生产者已产生了信息而消费者却没有来得及接受信息这种情况。为此,需要引入由一个或者若干个存储单元组成的临时存储区,以便存放生产者所产生的信息,平滑进程间由于速度不确定所带来的问题。这个临时存储区叫做缓冲区,通常用一维数组来表示。

  由一个或若干个存储单元组成的缓冲区叫作“有穷缓冲区”。下面我们来分析一下有穷缓冲的生产者和消费者的例子。

  假设有多个生产者和多个消费者,它们共享一个具有n个存储单元的有穷缓冲区Buffer(0……n-1),这是一个环形队列。其队尾指针Rear指向当前信息应存放的位置(Buffer[Rear]),队首指针Front指向当前取出信息的位置(Buffer[front])。生产者进程总是把信息存放在Buffer[Rear]中,消费者进程则总是从Buffer[Rear]中取出信息。如果想使生产者进程和消费者进程协调合作,则必须使它们遵循如下规则:

  1) 只要缓冲区有存储单元,生产者都可往其中存放信息;当缓冲区已满时,若任意生产者提出写要求,则都必须等待;

  2) 只要缓冲区中有消息可取,消费者都可从缓冲区中取出消息;当缓冲区为空时,若任意消费者想取出信息,则必须等待;

  3) 生产者们和消费者们不能同时读、写缓冲区。

  用JAVA 实现“生产者-消费者”问题的代码如下:

  class MonitorTest{

  static int produce_speed=200;

  static int consume_speed=200;

  public static void main (String [] args){

   if(args.length>0)

   produce_speed=Integer.parseInt(args[0]);

   if(args.length>1)

   consume_speed=Integer.parseInt(args[1]);

   Monitor monitor=new Monitor();

   new Producer(monitor,produce_speed);

   new Consumer(monitor,consume_speed);

   try{

   Thread.sleep(4000);

   }catch(InterruptedException e){}

   System.exit(0);

   }

  }

  class Monitor {

   int Buffer_Length=10;

   int[] Buffer=new int[Buffer_Length];

   int Item;

   int Count=0,Rear=0,Front=0;

   //get buffer

   synchronized int get(){

   if(Count ==0)

   try{

   wait();

   }catch(InterruptedException e){}

   Item=Buffer[Front];

   Count--;

   Front=(Front+1)%Buffer_Length;

   System.out.println("Got:"+Item);

   notify();

   return Item;

  }

  //set buffer

  synchronized void set(int value){

  if(Count==Buffer_Length)

   try{

   wait();

   }catch(InterruptedException e){}

   Buffer[Rear]=value;

   Count++;

   Rear=(Rear+1)%Buffer_Length;

   System.out.println("Set:"+value);

   notify();

   }

  }

  class Producer implements Runnable{

   Monitor monitor;

   int speed;

   Producer(Monitor monitor,int speed){

   This.monitor=monitor;

   This.speed=speed;

   new Thread(this,"Producer").start();

   }

   public void run(){

   int i=0;

   while(true){

   monitor.set(i++);

   try{

   Thread.sleep((int)(Math.random()*speed));

   }catch(InterruptedException e){}

   }

   }

  }

  class Consumer implements Runnable{

   Monitor monitor;

   int speed;

   Consumer(Monitor monitor,int speed){

   This.monitor=monitor;

   This.speed=speed;

   new Thread(this,"Consumer").start();

   }

   public void run(){

   while(true){

   monitor.get();

   try{

   Thread.sleep((int) (Math.random()*speed));

   }catch(InterruptedException e){}

   }

   }

  }

  上述程序在Windows 95的JDK 1.0.2下通过,它通过改变produce_speed 、consume_speed 来改变生产者进程和消费者进程的速度。