<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package locks;

import java.util.Optional;

public class RWLockSol extends RWLock {

	/**
	 * Number of active readers holding this lock.
	 * 
	 * Class Invariant: If this is non-zero, no writer is holding this lock.
	 */
	int numReaders = 0;

	/**
	 * Number of writers waiting for this lock.
	 * 
	 * Class Invariant: If this is non-zero, no new readers may acquire this lock.
	 */
	int numWritersWaiting = 0;

	/**
	 * Number of times the active writer is holding this lock, or 0 if not locked by
	 * a writer.
	 */
	int heldCount = 0;

	/**
	 * The active writer thread, or empty if not locked by a writer.
	 * 
	 * Class Invariant: If this is non-empty, no readers are holding this lock.
	 */
	Optional&lt;Thread&gt; writer = Optional.empty();

	Lock rdLock = new ReadLock();
	Lock wrLock = new WriteLock();

	public Lock readLock() {
		return rdLock;
	}

	public Lock writeLock() {
		return wrLock;
	}

	class ReadLock implements Lock {
		@Override
		public void lock() {
			synchronized (RWLockSol.this) {

				// A reader cannot enter while a writer is present, or
				// if a writer is waiting
				while (writer.isPresent() || numWritersWaiting != 0) {
					try {
						RWLockSol.this.wait();
					} catch (InterruptedException ignored) {
					}
				}

				// Increment number of readers currently holding this lock
				numReaders++;
			}
		}

		@Override
		public void unlock() {
			synchronized (RWLockSol.this) {
				numReaders--;

				// The only threads waiting while a reader has the lock
				// are incoming writers. Wake them up if all readers are gone.
				if (numReaders == 0) {
					RWLockSol.this.notifyAll();
				}
			}
		}
	}

	public class WriteLock implements Lock {
		@Override
		public void lock() {
			Thread me = Thread.currentThread();
			synchronized (RWLockSol.this) {

				// Reentrant lock: if we're already holding this lock, we can just grab it
				// again. This code already works; you need not modify it.
				if (writer.orElse(null) == me) {
					heldCount++;
					return;
				}

				// We are waiting for the lock
				numWritersWaiting++;

				// A writer cannot enter while another writer is present,
				// or while readers are present
				while (writer.isPresent() || numReaders &gt; 0) {
					try {
						RWLockSol.this.wait();
					} catch (InterruptedException ignored) {
					}
				}

				// Once a writer holds the lock, there is one less waiting writer,
				// and we must set the current writer thread correctly.
				numWritersWaiting--;
				writer = Optional.of(me);
				heldCount++;
			}
		}

		@Override
		public void unlock() {
			synchronized (RWLockSol.this) {
				heldCount--;
				if (heldCount &gt; 0) {
					// Reentrant lock: we still have this lock
					return;
				}
				writer = Optional.empty();
				RWLockSol.this.notifyAll();
			}
		}
	}
}
</pre></body></html>