Joseph Haugh
University of New Mexico

public class GroundCounter {
protected long count;
protected GroundCounter(long c) {
count = c;
}
protected long value() { return count; }
protected void inc() {
++count;
}
protected void dec() {
--count;
}
}
public class BoundedCounter extends GroundCounter {
private final long MIN, MAX;
public BoundedCounter(final long MIN, final long MAX) {
super(MIN);
this.MIN = MIN;
this.MAX = MAX;
}
public synchronized long value() { return super.value(); }
public synchronized void inc() {
while (value() >= MAX) {
try { wait(); } catch(InterruptedException e) {};
}
super.inc();
notifyAll();
}
public synchronized void dec() {
while (value() <= MIN) {
try { wait(); } catch(InterruptedException e) {};
}
super.dec();
notifyAll();
}
}
If all relevant variables and methods are declared protected the subclass can generally implement the desired policy
notify to
notifyAll
public class Stack {
public synchronized boolean isEmpty() {
// ...
}
public synchronized void push(Object x) {
// ...
}
public synchronized Object pop() throws StackEmptyException {
if (isEmpty()) {
throw new StackEmptyException();
} else {
// ...
}
}
}
public class WaitingStack extends Stack {
public synchronized void push(Object x) {
super.push(x);
notifyAll();
}
public synchronized Object pop() throws StackEmptyException {
while(isEmpty()) {
try {
wait();
} catch (InterruptedException e) {}
}
return super.pop();
}
}
A conflict set is a list of pairs of operations that cannot run concurrently
A conflict graph is a visual equivalent of the conflict set
The conflict graph makes it easy to see at a glance which operations are mutually exclusive and which can be parallelized
Finite state control describes how the policy is enforced at runtime using a state machine
This maps directly to the synchronized blocks that bracket
each operation in the implementation
public class Inventory extends GroundInventory {
protected int storing = 0;
protected int retrieving = 0;
public void store(String desc, Object item,
String supplier) {
synchronized (this) {
while (retrieving != 0) {
try { wait(); } catch (InterruptedException e) {}
}
++storing;
}
super.store(desc, item, supplier);
synchronized (this) {
if (--storing == 0) {
notifyAll();
}
}
}
public void retrieve(String desc, Object item,
String supplier) {
synchronized (this) {
while (storing != 0 || retrieving != 0) {
try { wait(); } catch (InterruptedException e) {}
}
++retrieving;
}
super.retrieve(desc, item, supplier);
synchronized (this) {
if (--retrieving == 0) {
notifyAll();
}
}
}

public abstract class ReadWrite {
protected int activeReaders = 0;
protected int activeWriters = 0;
protected int waitingReaders = 0;
protected int waitingWriters = 0;
protected abstract void doRead();
protected abstract void doWrite();
public void read() {
beforeRead();
doRead();
afterRead();
}
public void write() {
beforeWrite();
doWrite();
afterWrite();
}
protected synchronized void beforeRead() {
++waitingReaders;
while (!allowReader()) {
try { wait(); } catch (InterruptedException e) {}
}
--waitingReaders;
++activeReaders;
}
protected synchronized void afterRead() {
--activeReaders;
notifyAll();
}
protected synchronized void beforeWrite() {
++waitingWriters;
while (!allowWriter()) {
try { wait(); } catch (InterruptedException e) {}
}
--waitingWriters;
++activeWriters;
}
protected synchronized void afterWrite() {
--activeWriters;
notifyAll();
}
protected boolean allowReader() {
return activeWriters == 0;
}
protected boolean allowWriter() {
return activeReaders == 0 && activeWriters == 0;
}
protected boolean allowReader() {
return waitingWriters == 0 && activeWriters == 0;
}
protected boolean allowWriter() {
return activeReaders == 0 && activeWriters == 0;
}
private boolean canWrite;
public synchronized void afterRead() {
canWrite = true; // ...previous afterRead code...
}
public synchronized void afterWrite() {
canWrite = false; // ...previous afterWrite code...
}
protected boolean allowReader() {
if (waitingWriters > 0 && waitingReaders > 0) {
return !canWrite && activeWriters == 0;
}
return waitingWriters == 0 && activeWriters == 0;
}
protected boolean allowWriter() {
if (waitingWriters > 0 && waitingReaders > 0) {
return canWrite && activeWriters == 0;
}
return activeReaders == 0 && activeWriters == 0;
}
Suppose a legacy class measures temperature in Fahrenheit:
public class FSensor {
public double getTemp() {
/* returns degrees F */
}
}
An adapter wraps it to provide a Celsius interface:
public class CSensor {
private FSensor sensor;
public CSensor(FSensor sensor) {
this.sensor = sensor;
}
public double getTemperature() {
return (sensor.getTemp() - 32) * 5.0 / 9.0;
}
}
CelsiusSensor has no access to FahrenheitSensor’s internalsgetTemperature() in CelsiusThe interface is the same as that of the ground class

Different methods are provided and coded in terms of the ground class
public void reset() {
setFlightTime(0);
setLocation(new PosPoint());
setVelocity(new VelVec());
}
public void step(VelVec vel) {
flightTime++;
velocity = vel;
location.add(velocity);
}

Superposition: a process by which variables are introduced to monitor the state of the ground class
public void step(VelVec vel) {
flightTime++;
velocity = vel;
location.add(velocity);
if(velocity.compare(MAX_SAFE_VEL) > 0) {
unsafeCount++;
}
}


public synchronized void step(VelVec vel) {
// ...
notifyAll();
}
public synchronized void reset() {
// ...
notifyAll();
}
public synchronized boolean targetVelocity(VelVec vel) {
// mag returns integer magnitude of vector
while (mag(velocity) != 0 && mag(velocity) < mag(vel)) {
try { wait(); } catch (InterruptedException e) { }
}
if(mag(velocity) == 0) return false; // reset issued
else return true; // target velocity reached
}
notifyAll wakes waiting threads, but they do not resume immediately,
each must re-acquire the lock before continuing
reset sets velocity to 0 and calls notifyAlltargetVelocity can re-acquire the lock, step runs and sets velocity to a nonzero valuetargetVelocity finally resumes and checks mag(velocity) == 0, but it is no longer 0, so it incorrectly returns truevelocity after waking up does not reliably tell you why you woke uppublic synchronized void step(VelVec vel) {
// ...
notifyAll();
}
public synchronized void reset() {
// ...
tracking = false;
notifyAll();
}
public synchronized boolean targetVelocity(VelVec vel) {
tracking = true; // remains true unless reset
while (tracking && mag(velocity) < mag(vel)) {
try { wait(); } catch (InterruptedException e) { }
}
if(!tracking) return false;
tracking = false;
return true;
}
public synchronized void step(VelVec vel) {
flightTime++;
velocity = vel;
location.add(velocity);
Log.addEntry(flightTime, location);
}
class Log {
public static synchronized void addEntry(int time,
PosPoint loc) {
// store/print entry...
}
}
