...
This noncompliant code example consists of an application to monitor a sports race. Each racer is asociated with a dedicated object instance of class Racer
:.
Code Block |
---|
public class Racer implements Cloneable { private double currentSpeed; private double distanceTraveleddistance; public double getCurrentSpeed() { return currentSpeed; } public void setCurrentSpeed(double currentSpeed) { this.currentSpeed = currentSpeed; } public double getDistance() { return distanceTraveleddistance; } } |
Each racer has two statistics that can be reported about them: their current speed, and the current distance traveled. The class Racer
provides methods getCurrentSpeed()
and getDistance()
for this purpose.
The monitoring application is built upon class Race
which maintains a list of racers. To be thread-safe, it locks each racer before it reads her statistics until after it reports the average.
public void setDistance(double distance) {
this.distance = distance;
}
public Racer clone() {
try {
return (Racer) super.clone();
} catch (CloneNotSupportedException x) {
/* handle error */
}
return null;
}
}
|
Each racer has two statistics that can be reported about them: their current speed, and the current distance traveled. The class Racer
provides methods getCurrentSpeed()
and getDistance()
for this purpose.
The monitoring application is built upon class Race
which maintains a list of racers. To be thread-safe, it accepts a list of racers, and defensively clones them. Henceforth, any thread can change a Racer's distance or current speed, or get the average distance or average current speed of all racers. Changing a racer's statistics involves locking using the racer's intrinsic lock, while getting the average statistics for all racers involves locking all the racers' intrinsic locks until the average is calculated.
Code Block | ||
---|---|---|
| ||
public class Race {
private final Racer[] racers;
public Race(Racer[] racers) {
this.racers = cloneRacers( 0, racers);
}
// Defensively clone the racers array, but only after all racers are locked
private Racer[] cloneRacers(int i, Racer[] racers) {
if (i > racers.length - 1) {
Racer[] result = new Racer[i];
for (int j = 0; j < this.racers.length; j++) {
result[j] = racers[j].clone();
}
return result;
}
synchronized(racers[i]) {
return cloneRacers( ++i, racers);
}
}
public void setCurrentSpeed(int index, double currentSpeed) {
synchronized( racers[index]) {
racers[index].setCurrentSpeed( currentSpeed);
}
}
public void setDistance(int index, double distance) {
synchronized( racers[index] | ||
Code Block | ||
| ||
public class Race { private final Racer[] racers; // For thread-safety, caller must relinquich any references to racers public Race(Racer[] racers) { this.racers = racers[index].setDistance( distance); } } double getAverageCurrentSpeed() { return averageCurrentSpeedCalculator(0, 0.0); } double averageCurrentSpeedCalculator(int i, double currentSpeed) { // Acquires locks in increasing order if (i > racers.length - 1) { return currentSpeed / racers.length; } synchronized(racers[i]) { currentSpeed += racers[i].getCurrentSpeed(); return averageCurrentSpeedCalculator(++i, currentSpeed); } } double getAverageDistance() { return averageDistanceCalculator(racers.length - 1, 0.0); } double averageDistanceCalculator(int i, double distance) { // Acquires locks in decreasing order if (i <= -1) { return distance / racers.length; } synchronized(racers[i]) { distance += racers[i].getDistance(); return averageDistanceCalculator(--i, distance); } } } |
...
Code Block | ||
---|---|---|
| ||
public class Race { double getAverageCurrentSpeed() { return averageCurrentSpeedCalculator(0, 0.0); } double averageCurrentSpeedCalculator(int i, double currentSpeed) { // Acquires locks in increasing order if (i > racers.length - 1) { return currentSpeed / racers.length; } synchronized(racers[i]) { currentSpeed += racers[i].getCurrentSpeed(); return averageCurrentSpeedCalculator(++i, currentSpeed); } } double getAverageDistance() { return averageDistanceCalculator(0, 0.0); } double averageDistanceCalculator(int i, double distance) { // Acquires locks in increasing order if (i > racers.length - 1) { return distance / racers.length; } synchronized(racers[i]) { distance += racers[i].getDistance(); return averageDistanceCalculator(++i, distance); } } } |
...