import Utilities.*; class Racer extends MyObject implements Runnable { private int M = 0; private long sum = 0; // `volatile' no longer needed private Object mutex = null; // implicit binary semaphore public Racer(String name, int M) { super(name); this.M = M; // use `this' object for synchronization since both threads execute in mutex = this; // a single object; also can use mutex = new Object(); System.out.println("age()=" + age() + ", " + getName() + " is alive, M=" + M); } private long fn(long j, int k) { long total = j; for (int i = 1; i <= k; i++) total += i; return total; } public void run() { System.out.println("age()=" + age() + ", " + getThreadName() + " is running"); for (int m = 1; m <= M; m++) synchronized (mutex) { // implied P(mutex) sum = fn(sum, m); } // implied V(mutex) System.out.println("age()=" + age() + ", " + getThreadName() + " is done, sum = " + sum); } } class RaceTwoThreads extends MyObject { private static int M = 10; private final static int numRacers = 2; public static void main(String[] args) { // parse command line arguments, if any, to override defaults GetOpt go = new GetOpt(args, "UtM:"); go.optErr = true; String usage = "Usage: -t -M m"; int ch = -1; boolean timeSlicingEnsured = false; while ((ch = go.getopt()) != go.optEOF) { if ((char)ch == 'U') { System.out.println(usage); System.exit(0); } else if ((char)ch == 't') timeSlicingEnsured = true; else if ((char)ch == 'M') M = go.processArg(go.optArgGet(), M); else { System.err.println(usage); System.exit(1); } } System.out.println("RaceTwoThreads: M=" + M + ", timeSlicingEnsured=" + timeSlicingEnsured); // enable time slicing Solaris (50 msec); noop on Windows 95 if (timeSlicingEnsured) ensureTimeSlicing(50); // so threads share CPU // start the two threads, both in the same object // so they share one instance of its variable sum Racer racerObject = new Racer("RacerObject", M); Thread[] racer = new Thread[numRacers]; for (int i = 0; i < numRacers; i++) racer[i] = new Thread(racerObject, "RacerThread" + i); for (int i = 0; i < numRacers; i++) racer[i].start(); System.out.println("age()=" + age() + ", all Racer threads started"); // wait for them to finish try { for (int i = 0; i < numRacers; i++) racer[i].join(); } catch (InterruptedException e) { System.err.println("interrupted out of join"); } // correct race-free final value of sum is 2*220 = 440 for M of 10 // and 2*1335334000 = 2670668000 for M of 2000 (so `long sum' needed) System.out.println("RaceTwoThreads done"); System.exit(0); } } /* ............... Example compile and run(s) D:\>javac norc.java D:\>java RaceTwoThreads Java version=1.1.1, Java vendor=Sun Microsystems Inc. OS name=Windows 95, OS arch=x86, OS version=4.0 Wed Jul 02 17:01:15 EDT 1997 RaceTwoThreads: M=10, timeSlicingEnsured=false age()=60, RacerObject is alive, M=10 age()=60, all Racer threads started age()=60, RacerThread0 is running age()=60, RacerThread0 is done, sum = 220 age()=60, RacerThread1 is running age()=60, RacerThread1 is done, sum = 440 RaceTwoThreads done D:\>java RaceTwoThreads -M2000 RaceTwoThreads: M=2000, timeSlicingEnsured=false age()=60, RacerObject is alive, M=2000 age()=60, all Racer threads started age()=60, RacerThread0 is running age()=60, RacerThread1 is running age()=2370, RacerThread1 is done, sum = 2540975095 age()=2420, RacerThread0 is done, sum = 2670668000 RaceTwoThreads done % javac norc.java % java RaceTwoThreads -M2000 -t Java version=1.1_Final, Java vendor=Sun Microsystems Inc. OS name=Solaris, OS arch=sparc, OS version=2.x Tue Jul 01 14:00:42 PDT 1997 RaceTwoThreads: M=2000, timeSlicingEnsured=true Scheduler: timeSlice=50 randomSlice=false priority=10 age()=19, RacerObject is alive, M=2000 age()=21, all Racer threads started age()=22, RacerThread0 is running age()=68, RacerThread1 is running age()=2992, RacerThread0 is done, sum = 2093590456 age()=3473, RacerThread1 is done, sum = 2670668000 RaceTwoThreads done ... end of example run(s) */