public class ReadersWriters2 {
	private class ConditionVariable {
		public boolean wantToSleep=false;
	}
	private int readers=0;
	private int waitingReaders=0;
	private int waitingWriters=0;
	private boolean writing=false;
	private ConditionVariable okToRead=new ConditionVariable();
   private ConditionVariable okToWrite=new ConditionVariable();
	public void startWrite() throws InterruptedException {
		synchronized (okToWrite) { // get condition variable lock
			synchronized (this) { // get monitor lock
				if (writing || readers>0) {
					waitingWriters++;
					okToWrite.wantToSleep=true;
				} else {
					writing=true;
					okToWrite.wantToSleep=false;
				}
			} //give up monitor lock
			if (okToWrite.wantToSleep) 
				okToWrite.wait(); 
		}    
	}
	public void stopWrite() {
		synchronized (okToRead) {
			synchronized (okToWrite) {
				synchronized (this) {
					if (waitingWriters>0) {
						waitingWriters--;
						okToWrite.notify(); // wakeup one writer
					} else {
						writing=false;
						readers=waitingReaders;
						waitingReaders=0;
						okToRead.notifyAll(); // wakeup all readers
					}
				}
			}
		}      
	}
	public void startRead() throws InterruptedException { 
		synchronized (okToRead) {
			synchronized (this) {
				if (writing || waitingWriters>0) {
					waitingReaders++;
					okToRead.wantToSleep=true;
				} else {
					readers++;
					okToRead.wantToSleep=false;
				} 
			}
			if (okToRead.wantToSleep) 
				okToRead.wait();
		}
	}
	public void stopRead() {
		synchronized (okToWrite) {
			synchronized (this) {
				readers--;
				if (readers==0 && waitingWriters>0) {
					waitingWriters--;
					writing=true;
					okToWrite.notify(); // wakeup one writer
				}
			}
		}
	}  
}

