class ReadWriteMonitor {
    private int read_c = 0;
    private boolean write_active = false;
    private Boolean write_ok, read_ok = new Boolean(true);
    int item = 0;

    public synchronized void beginRead() {
	if (write_active) {
	    try {read_ok.wait();
	    } catch (Exception e) {}
	}
	read_c ++;
    }

    public synchronized void endRead() {
	read_c --;
	if (read_c==0) write_ok.notify();
    }

    public synchronized void beginWrite() {
	if (read_c!=0 | write_active) {
	    try {
		write_ok.wait();
	    } catch (Exception e) {}
	write_active = true;
	}
    }

    public synchronized void endWrite() {
	write_active = false;
	read_ok.notifyAll();
	write_ok.notify();
    }
}

class Reader extends Thread {
    ReadWriteMonitor rwm;
    String name;
    
    public Reader(String n, ReadWriteMonitor m) {
	rwm = m;
	name = n;
    }

    public void run() {
        for (int i=0; i<20; i++)  {
	    try {
		sleep(500);
		System.out.print("Reader " + name + " read: ");
		rwm.beginRead();
		System.out.println(rwm.item);
		rwm.endRead();
	    } catch (Exception e) {}
	}
    }
}

class Writer extends Thread {
    ReadWriteMonitor rwm;
    String name;
    
    public Writer(String n, ReadWriteMonitor m) {
	rwm = m;
	name = n;
    }

    public void run() {
        for (int i=0; i<20; i++) {
	    int r = (int)(Math.random() * 100);
	    try {
		sleep(500);
		System.out.print("Writer " + name + " written: ");
	        rwm.beginWrite();
		System.out.println(r);
		rwm.item = r;
		rwm.endWrite();
	    } catch (Exception e) {}
	}
    }
}

	
public class Test {
    private static ReadWriteMonitor rwm = new ReadWriteMonitor();

    public static void main(String[] args) {
	for (int i=0; i<10; i++) {
	    Reader r = new Reader(String.valueOf(i), rwm);
	    r.start();
	}

	for (int i=0; i<5; i++) {
	    Writer w = new Writer(String.valueOf(i), rwm);
	    w.start();
	}
    }
}

