Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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
bgColor#FFcccc

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
bgColor#FFcccc

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
bgColor#ccccff
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);
    }
  }
}

...