Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: (fix) Method and block synch cannot declare itemsInInventory to be final (the field needs to be mutable)

Wiki Markup
Composite operations consisting of more than one discrete operation are, by definition, non-atomic. For example, the Java expression {{x+\+}} is non-atomic because it is a composite operation consisting of three discrete operations: reading the current value of {{x}}, adding one to it, and writing the new, incremented value back to {{x}}.  Errors can arise from composite operations that need to be perceived atomically but are not. \[[JLS 05|AA. Java References#JLS 05]\]. 

For atomicity of a grouping of calls to independently atomic methods of the existing Java API, see CON07-J. Do not assume that a grouping of calls to independently atomic methods is atomic.

...

Code Block
bgColor#FFcccc
private int itemsInInventory = 100;

public final int removeItem() {
  if (itemsInInventory > 0) {
    return itemsInInventory--;  // Returns new count of items in inventory
  } 
  return -1; // Error code  
}

public final int returnItem() {
  if (itemsInInventory == Integer.MAX_VALUE) { // Check for integer overflow
    return -1; // Error Code
  } 
  return itemsInInventory++;
}

...

Code Block
bgColor#FFcccc
private volatile int itemsInInventory = 100;

public final int removeItem() {
  if (itemsInInventory > 0) {
    return itemsInInventory--;  // Returns new count of items in inventory
  } 
  return -1; // Error code  
}

public final int returnItem() {
  if (itemsInInventory == Integer.MAX_VALUE) { // Check for integer overflow
    return -1; // Error Code
  } 
  return itemsInInventory++; 
}

Volatile variables are unsuitable when more than one read/write operation needs to be atomic. The use of a volatile variable in this noncompliant code example guarantees that once itemsInInventory has been updated, the new value is visible to all threads that read the field. However, because the post decrement operator is nonatomic, even when volatile is used, the interleaving described in the previous noncompliant code example is still possible.

...

Code Block
bgColor#ccccff
private final AtomicInteger itemsInInventory = new AtomicInteger(100);

private final int removeItem() {
  for (;;) {
    int old = itemsInInventory.get();
    if (old > 0) {
      int next = old - 1; // Decrement 
      if (itemsInInventory.compareAndSet(old, next)) {
        return next;  // Returns new count of items in inventory
      }
    } else {
      return -1; // Error code
    }
  }
}

...

Wiki Markup
\[AtomicInteger is an\] {{int}} value that may be updated atomically. An {{AtomicInteger}} is used in applications such as atomically incremented counters, and cannot be used as a replacement for an {{Integer}}. However, this class does extend {{Number}} to allow uniform access by tools and utilities that deal with numerically-based classes. 

Wiki Markup
The {{compareAndSet()}} method takes two arguments, the expected value of a variable when the method is invoked and the updated value. This compliant solution uses this method to atomically set the value of {{itemsInInventory}} to the updated value if and only if the current value equals the expected value \[[API 06|AA. Java References#API 06]\].  The {{for}} loop guarantees the same behavior of the original function, namely that the function succeeds in decrementing {{itemsInInventory}} or an error code is returned.

...

Code Block
bgColor#ccccff
private final int itemsInInventory = 100;

public final synchronized int removeItem() {
  if (itemsInInventory > 0) {
    return itemsInInventory--;  // Returns new count of items in inventory
  } 
  return -1; // Error Code 
}

public synchronized final int returnItem() {
  if (itemsInInventory == Integer.MIN_VALUE) { // Check for integer overflow
    return -1;
  } 
  return itemsInInventory++;
}

...

Code Block
bgColor#ccccff
private final int itemsInInventory = 100;

public int removeItem() {
  synchronized(this) {
    if (itemsInInventory > 0) {
      return itemsInInventory--;  // Returns new count of items in inventory    
    } 
    return -1; // Error code
  }
}

public final int returnItem() {
  synchronized(this) {
    if (itemsInInventory == Integer.MIN_VALUE) { // Check for integer overflow
      return -1;
    } 
    return itemsInInventory++;
  }
}

...

Code Block
bgColor#ccccff
private int itemsInInventory = 100;
private final Lock lock = new ReentrantLock();
    
public int removeItem() {
  Boolean myLock = false;
    
  try {
    myLock = lock.tryLock(); 
    	
    if (itemsInInventory > 0) {
      return itemsInInventory--;
    }  
  } finally {
    if (myLock) {
      lock.unlock();
    }
  }
  return -1; // Error code
}

...

Code Block
bgColor#ccccff
public int returnItem() {
  Boolean myLock = false;
    
  try {
    myLock = lock.tryLock(); 
    	
    if (itemsInInventory == Integer.MIN_VALUE) { // Check for integer overflow
      return -1;
    } 
    return itemsInInventory++;
  } finally {
    if (myLock) {
      lock.unlock();
    }
  }
  return -1; // Error code
}

...

Code Block
bgColor#FFcccc
private volatile int a;
private volatile int b;

public int getSum() throws ArithmeticException {
  // Check for integer overflow
  if( b > 0 ? a > Integer.MAX_VALUE - b : a < Integer.MIN_VALUE - b ) { 
    throw new ArithmeticException("Not in range");
  }

  return a + b;
}

public void setValues(int a, int b) {
  this.a = a;
  this.b = b;
}

...

Code Block
bgColor#ccccff
private int a;
private int b;

public synchronized int getSum() throws ArithmeticException {
  // Check for integer overflow
  if( b > 0 ? a > Integer.MAX_VALUE - b : a < Integer.MIN_VALUE - b ) { 
    throw new ArithmeticException("Not in range");
  }

  return a + b;
}

public synchronized void setValues(int a, int b) {
  this.a = a;
  this.b = b;
}

...

Wiki Markup
\[[API 06|AA. Java References#API 06]\] Class AtomicInteger
\[[JLS 05|AA. Java References#JLS 05]\] [Chapter 17, Threads and Locks|http://java.sun.com/docs/books/jls/third_edition/html/memory.html], section 17.4.5 Happens-before Order, section 17.4.3 Programs and Program Order, section 17.4.8 Executions and Causality Requirements
\[[Tutorials 08|AA. Java References#Tutorials 08]\] [Java Concurrency Tutorial|http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html]
\[[Lea 00|AA. Java References#Lea 00]\] Sections, 2.2.7 The Java Memory Model, 2.2.5 Deadlock, 2.1.1.1 Objects and locks
\[[Bloch 08|AA. Java References#Bloch 08]\] Item 66: Synchronize access to shared mutable data
\[[Daconta 03|AA. Java References#Daconta 03]\] Item 31: Instance Variables in Servlets
\[[JavaThreads 04|AA. Java References#JavaThreads 04]\] Section 5.2 Atomic Variables
\[[Goetz 06|AA. Java References#Goetz 06]\] 2.3. "Locking"
\[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 667|http://cwe.mitre.org/data/definitions/667.html] "Insufficient Locking", [CWE ID 413|http://cwe.mitre.org/data/definitions/413.html] "Insufficient Resource Locking", [CWE ID 366|http://cwe.mitre.org/data/definitions/366.html]  "Race Condition within a Thread", [CWE ID 567|http://cwe.mitre.org/data/definitions/567.html]  "Unsynchronized Access to Shared Data"

...