public class producer_consumer_fwn {
    public static void main(String[] args) {
        Object the_monitor=new Object();
        The_Store_wn a_store=new The_Store_wn();
        Consumer_wn c0 = new Consumer_wn(a_store,the_monitor,0);
        c0.setPriority( Thread.NORM_PRIORITY );
        Consumer_wn c1 = new Consumer_wn(a_store,the_monitor,1);
        c1.setPriority( Thread.NORM_PRIORITY );
        Producer_wn p1 = new Producer_wn(a_store,the_monitor);
        p1.setPriority( Thread.MAX_PRIORITY );
        if (args[0].equals("1") ) {
            c1.start();
            c0.start();
            p1.start();
        } else {
            p1.start();
            c1.start();
            c0.start();
        }
    }
}

class The_Store_wn {
    public   int the_count=5;
    public   int the_number=0;
    public boolean[] got_it=new boolean[]{false,false};
    public The_Store_wn(){
    }
    public  int get() {
        return the_number;
    }

    public void put() {
        the_number++;
        return;
    }

}

class Consumer_wn extends Thread {
    The_Store_wn ts;
    Object the_mon;
    int this_consumer;
    public Consumer_wn(The_Store_wn tsget,Object mon,int the_consumer) {
        ts=tsget;
        the_mon=mon;
        this_consumer=the_consumer;
    }

    public void run() {
        synchronized(the_mon) {
            System.out.println("Consumer "+this_consumer+" starts" );
            try {
                System.out.println("Consumer "+this_consumer+"  wait() " );
                the_mon.wait();
            } catch (InterruptedException e) {
            }


            while (ts.the_number != ts.the_count) {
                if (ts.got_it[this_consumer]!=true) {
                    ts.got_it[this_consumer]=true;
                    System.out.println("                        Consumer "+this_consumer+"  # = " + ts.get());
                    //   ts.got_it[this_consumer]=true;
                }
                System.out.println("Consumer "+this_consumer+" notify() " );
                the_mon.notify();
                try {
                    System.out.println("Consumer "+this_consumer+" wait() " );
                    the_mon.wait();
                } catch (InterruptedException e) {
                }
            }
            System.out.println("                        Consumer "+this_consumer+"  # = " + ts.get());
            the_mon.notify();
            return;
        }
    }

}

class Producer_wn extends Thread {
    The_Store_wn ts;
    Object the_mon;
    public Producer_wn(The_Store_wn ts_get,Object mon) {
        ts=ts_get;
        the_mon=mon;
    }

    public void run() {

        synchronized (the_mon){
            System.out.println("Producer starts" );
            while (ts.the_number != ts.the_count) {
                ts.put();
                ts.got_it[0]=ts.got_it[1]=false;
                System.out.println("                        Producer    # = " + ts.the_number);
                while (!(ts.got_it[0]&&ts.got_it[1])) {
                    System.out.println("Consumers not finished");
                    the_mon.notify();
                    if (ts.the_number == ts.the_count) {
                        return;
                    }
                    try {
                        the_mon.wait();
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println("Producer notify() " );
                the_mon.notify();
                if (ts.the_number == ts.the_count) {
                    return;
                } else {
                    try {
                        System.out.println("Producer wait() " );
                        the_mon.wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
        }
    }
}