import Utilities.*; class Lock { // Lock is unlocked when owner == null // else lock is held by owner thread private Thread owner = null; // initial state is always unlocked public Lock() {super();} public synchronized void lock() { Thread who = Thread.currentThread(); if (owner == who) return; // allow owner to relock silently else if (owner == null) { owner = who; return; } else /* owner != who && owner != null */ { while (owner != null) { // since ``barging'' is possible in try { // Java monitors, a while loop is needed wait(); // even though only one thread is awakened } catch (InterruptedException e) {} // here `owner' can be null or another thread if it barged in } owner = who; return; } } public synchronized void unlock() throws IllegalMonitorStateException { Thread who = Thread.currentThread(); // allow unlocked lock if (owner == null) return; // to be unlocked silently else if (owner != who) { throw new IllegalMonitorStateException(); } else /* owner == who */ { owner = null; notify(); // at most one thread can proceed if } // any are waiting so notifyAll() not } // needed } class Node extends MyObject implements Runnable { private int id = 0; private int napOutsideLock = 0; // both are in private int napInsideLock = 0; // milliseconds private Lock arb = null; public Node(String name, int id, int napOutsideLock, int napInsideLock, Lock arb) { super(name + " " + id); this.id = id; this.napOutsideLock = napOutsideLock; this.napInsideLock = napInsideLock; this.arb = arb; System.out.println(getName() + " is alive, napOutsideLock=" + napOutsideLock + ", napInsideLock=" + napInsideLock); new Thread(this).start(); } private void outsideLock() { int napping; napping = ((int) random(napOutsideLock)) + 1; System.out.println("age()=" + age() + ", " + getName() + " napping without lock for " + napping + " ms"); nap(napping/2); if (random() >= 0.5) { System.out.println("age()=" + age() + ", " + getName() + " unlocking non-owned lock"); try { arb.unlock(); } catch (IllegalMonitorStateException e) { System.out.println("(outsideLock) " + e); } } nap(napping/2); } private void insideLock() { int napping; napping = ((int) random(napInsideLock)) + 1; System.out.println("age()=" + age() + ", " + getName() + " napping with lock for " + napping + " ms"); nap(napping/2); if (random() >= 0.5) { System.out.println("age()=" + age() + ", " + getName() + " relocking lock"); arb.lock(); } nap(napping/2); } public void run() { while (true) { outsideLock(); System.out.println("age()=" + age() + ", " + getName() + " wants to lock"); arb.lock(); insideLock(); try { arb.unlock(); } catch (IllegalMonitorStateException e) { System.out.println("(insideLock) " + e); } } } } class Locking extends MyObject { public static void main(String[] args) { // parse command line options, if any, to override defaults GetOpt go = new GetOpt(args, "Un:R:"); go.optErr = true; String usage = "Usage: -n numNodes -R runTime napOutsideLock[i]" + " napInsideLock[i] i=0,1,..."; int ch = -1; int numNodes = 2; int runTime = 60; // seconds while ((ch = go.getopt()) != go.optEOF) { if ((char)ch == 'U') { System.out.println(usage); System.exit(0); } else if ((char)ch == 'n') numNodes = go.processArg(go.optArgGet(), numNodes); else if ((char)ch == 'R') runTime = go.processArg(go.optArgGet(), runTime); else { System.err.println(usage); System.exit(1); } } System.out.println("Locking: numNodes=" + numNodes + ", runTime=" + runTime); // process non-option command line arguments int[] napOutsideLock = new int[numNodes]; int[] napInsideLock = new int[numNodes]; for (int i = 0; i < numNodes; i++) { napOutsideLock[i] = 8; napInsideLock[i] = 2; } int argNum = go.optIndexGet(); for (int i = 0; i < numNodes; i++) { napOutsideLock[i] = go.tryArg(argNum++, napOutsideLock[i]); napInsideLock[i] = go.tryArg(argNum++, napInsideLock[i]); } // create the Lock object Lock arb = new Lock(); // create the Nodes (self-starting threads) for (int i = 0; i < numNodes; i++) new Node("Node", i, napOutsideLock[i]*1000, napInsideLock[i]*1000, arb); System.out.println("All Node threads started"); // let the Nodes run for a while nap(runTime*1000); System.out.println("age()=" + age() + ", time to stop the threads and exit"); System.exit(0); } } /* ............... Example compile and run(s) D:\>javac lock.java D:\>java Locking -n5 -R10 Locking: numNodes=5, runTime=10 Node 0 is alive, napOutsideLock=8000, napInsideLock=2000 Node 1 is alive, napOutsideLock=8000, napInsideLock=2000 Node 2 is alive, napOutsideLock=8000, napInsideLock=2000 Node 3 is alive, napOutsideLock=8000, napInsideLock=2000 Node 4 is alive, napOutsideLock=8000, napInsideLock=2000 All Node threads started age()=220, Node 1 napping without lock for 5033 ms age()=220, Node 2 napping without lock for 5161 ms age()=220, Node 3 napping without lock for 1795 ms age()=220, Node 4 napping without lock for 2010 ms age()=220, Node 0 napping without lock for 4523 ms age()=1150, Node 3 unlocking non-owned lock age()=2030, Node 3 wants to lock age()=2030, Node 3 napping with lock for 144 ms age()=2190, Node 3 napping without lock for 1327 ms age()=2250, Node 4 wants to lock age()=2250, Node 4 napping with lock for 1290 ms age()=2520, Node 0 unlocking non-owned lock (outsideLock) java.lang.IllegalMonitorStateException age()=2740, Node 1 unlocking non-owned lock (outsideLock) java.lang.IllegalMonitorStateException age()=2910, Node 4 relocking lock age()=3570, Node 3 wants to lock age()=3570, Node 4 napping without lock for 533 ms age()=3570, Node 3 napping with lock for 1529 ms age()=3840, Node 4 unlocking non-owned lock (outsideLock) java.lang.IllegalMonitorStateException age()=4120, Node 4 wants to lock age()=4770, Node 0 wants to lock age()=5100, Node 3 napping without lock for 4510 ms age()=5100, Node 4 napping with lock for 1948 ms age()=5270, Node 1 wants to lock age()=5380, Node 2 wants to lock age()=6090, Node 4 relocking lock age()=7080, Node 4 napping without lock for 3053 ms age()=7080, Node 0 napping with lock for 2 ms age()=7080, Node 0 relocking lock age()=7080, Node 0 napping without lock for 5275 ms age()=7080, Node 1 napping with lock for 540 ms age()=7630, Node 1 napping without lock for 7259 ms age()=7630, Node 2 napping with lock for 1593 ms age()=8620, Node 4 unlocking non-owned lock (outsideLock) java.lang.IllegalMonitorStateException age()=9220, Node 2 napping without lock for 2431 ms age()=9660, Node 3 wants to lock age()=9660, Node 3 napping with lock for 157 ms age()=9720, Node 3 relocking lock age()=9720, Node 0 unlocking non-owned lock (outsideLock) java.lang.IllegalMonitorStateException age()=9830, Node 3 napping without lock for 6246 ms age()=10160, Node 4 wants to lock age()=10160, Node 4 napping with lock for 1920 ms age()=10210, time to stop the threads and exit ... end of example run(s) */