Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: changed doSomething() to somethingMoreMeaningful()

...

Code Block
bgColor#FFCCCC
class RaceCollection {
  private List<InetAddress> ips = Collections.synchronizedList(new ArrayList<InetAddress>());
  
  public void addIPAddress(InetAddress ia) {
    // Validate
    ips.add(ia);
  }
  
  public void doSomethingaddAndPrintIP() throws UnknownHostException {
    addIPAddress(InetAddress.getLocalHost());
    InetAddress[] ia = (InetAddress[]) ips.toArray(new InetAddress[0]);      
    System.out.println("Number of IPs: " + ia.length);     
  }
}

When the doSomethingaddAndPrintIP() method is invoked on the same object from multiple threads, the output, consisting of varying array lengths, indicates a race condition between the threads. In other words, the statements that are responsible for adding an IP address and printing it out are not sequentially consistent. Also note that the operations within a thread's run() method are non-atomic.

...

This noncompliant code example extends the base class and synchronizes on the doSomethingaddAndPrintIP() method which is required to be atomic.

Code Block
bgColor#FFCCCC
class RaceCollectionSub extends RaceCollection {
  public synchronized void doSomethingaddAndPrintIP() throws UnknownHostException {
    addIPAddress(InetAddress.getLocalHost());
    InetAddress[] ia = (InetAddress[]) ips.toArray(new InetAddress[0]);      
    System.out.println("Number of IPs: " + ia.length);     
  }
}

...

This noncompliant code example appears to use synchronization when defining the doSomethingaddAndPrintIP() method, however, it acquires an intrinsic lock instead of the lock of the List object. This means that another thread may modify the value of the List instance when the doSomethingaddAndPrintIP() method is executing.

Code Block
bgColor#FFCCCC
class Helper {
  public List<InetAddress> ips = Collections.synchronizedList(new ArrayList<InetAddress>());
  
  public synchronized void addIPAddress(InetAddress ia) {
    // Validate
    ips.add(ia);
  }

  public synchronized void doSomethingaddAndPrintIP() throws UnknownHostException {   
    addIPAddress(InetAddress.getLocalHost());
    InetAddress[] ia = (InetAddress[]) ips.toArray(new InetAddress[0]);     
    System.out.println("Number of IPs: " + ia.length); 
  }
}

...

Code Block
bgColor#ccccff
public void addIPAddress(InetAddress ia) { 
  synchronized(ips) { // Also synchronize this method
    // Validate
    ips.add(ia);
  }
}

public void doSomethingaddAndPrintIP() throws UnknownHostException {
  synchronized(ips) {
    addIPAddress(InetAddress.getLocalHost());
    ia = (InetAddress[]) ips.toArray(new InetAddress[0]);           
    System.out.println("Number of IPs: " + ia.length); 
  }
}

...

Code Block
bgColor#ccccff
class CompositeCollection {
  private List<InetAddress> ips;
 
  public CompositeCollection(List<InetAddress> list) {
    this.ips = list;
  }
  
  public synchronized void addIPAddress(InetAddress ia) {
    // Validate
    ips.add(ia);
  }

  public synchronized void doSomethingaddAndPrintIP() throws UnknownHostException {  
    addIPAddress(InetAddress.getLocalHost()); 
    InetAddress[] ia = (InetAddress[]) ips.toArray(new InetAddress[0]);     
    System.out.println("Number of IPs: " + ia.length); 
  }
}

...