import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.Random;
import java.util.Date;

/**
* Test class which encapsulates a Producer and Consumer (created
* using a simple object hierarchy). Main method starts one producer
* and one consumer using the same mailbox, and they each take and put
* 10 messages (each message is a date).
*
* See if you can explain the output you get from running this; try
* looking at output from different runs. You might also consider
* seeing what happens if you give one of them (producer or consumer)
* longer sleep times than the other.
*/
public class ProducerConsumer {
   
private static final int size = 10;
   
private static Random random = new Random();

   
/**
     * User of a mailbox implemented as a BlockingQueue.
     */
   
private static abstract class MailboxUser<T> {
       
protected BlockingQueue<T> mailbox;

       
public MailboxUser(BlockingQueue<T> mailbox) {
           
this.mailbox = mailbox;
       
}
    }

   
/**
     * Sample Producer which puts 10 dates into the mailbox. Sleeps a
     * random amount between 0 and 1 second between each put.
     */
   
private static class Producer extends    MailboxUser<Date>
                                 
implements Runnable {
       
public Producer(BlockingQueue<Date> mailbox) {
           
super(mailbox);
       
}
       
public void run() {
           
for(int i = 0; i < 10; ++i) {
               
Date date = new Date();
               
try {
                   
mailbox.put(date);
                    System.out.println
("Produced " + date);
                    Thread.sleep
(random.nextInt(1000));
               
} catch(InterruptedException e) {
                   
System.err.println("Producer interrupted");
               
}
            }
        }
    }

   
/**
     * Sample consumer which takes 10 dates from the mailbox. Sleeps a
     * random amount between 0 and 1 second between each take.
     */
   
private static class Consumer extends    MailboxUser<Date>
                                 
implements Runnable {
       
public Consumer(BlockingQueue<Date> mailbox) {
           
super(mailbox);
       
}
       
public void run() {
           
for(int i = 0; i < 10; ++i) {
               
try {
                   
Date date = mailbox.take();
                    System.out.println
("Consumed " + date);
                    Thread.sleep
(random.nextInt(1000));
               
} catch(InterruptedException e) {
                   
System.err.println("Consumer interrupted");
               
}
            }
        }
    }

   
public static void main(String[] args) {
       
ArrayBlockingQueue<Date> mailbox = new ArrayBlockingQueue<Date>(size);
       
new Thread(new Producer(mailbox)).start();
       
new Thread(new Consumer(mailbox)).start(); // Same mailbox!!
   
}
}