Versions Compared

Key

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

Declaring shared variables as volatile ensures visibility and limits reordering of accesses. Volatile accesses do not guarantee the atomicity of composite operations such as incrementing a variable (CON01-J. Design APIs that ensure atomicity of composite operations and visibility of results).

A write to a volatile field happens-before every subsequent read of that field. Statements that occur before the write to the volatile field also happen-before the read of the volatile field.

Declaring variables as volatile establishes a happens-before relationship such that a write to the volatile variable is always seen by a subsequent read. Consequently, these operations appear to be sequentially consistent with respect to each other. Statements that occur before the write to the volatile field also happen-before the read of the volatile field.

Consider two threads that are executing some statements:

...

Volatile read and write operations cannot be reordered with respect to each other and also with respect to nonvolatile variables accesses. When Thread 2 reads the volatile variable it will see sees the results of all the writes occurring before the write to the volatile variable in Thread 1.

...

This noncompliant code example declares a non-volatile int variable that nonvolatile variable of type int which is initialized in the constructor depending on a security check. In a multi-threading scenario, it is possible that the statements will be reordered so that the boolean flag initialized is set to true before the initialization has concluded. If it is possible to obtain a partially initialized instance of the class in a subclass using a finalizer attack (OBJ04-J. Do not allow partially initialized objects to be accessed), a race condition can be exploited by invoking the getBalance() method to obtain the balance even though initialization is still underway.

Code Block
bgColor#FFcccc
class BankOperation {
  private int balance = 0;
  private boolean initialized = false;
 
  public BankOperation() {
    if (!performAccountVerification()) {
      throw new SecurityException("Invalid Account"); 
    }
    balance = 1000;   
    initialized = true; 
  }
  
  private int getBalance() {
    if (initialized == true) {
      return balance;
    }
    else {
      return -1;
    }
  }
}

In a multi-threading scenario, it is possible that the statements will be reordered so that the boolean flag initialized is set to true before the initialization has concluded. If it is possible to obtain a partially initialized instance of the class in a subclass using a finalizer attack (OBJ04-J. Do not allow partially initialized objects to be accessed), a race condition can be exploited by invoking the getBalance() method to obtain the balance even though initialization is still underway.

Compliant Solution (volatile guard)

...

This noncompliant code example consists of two classes, an immutable ImmutablePoint class and a mutable Holder class. Holder is mutable because a new ImmutablePoint instance can be assigned to it using the setPoint() method. If one thread updates the value of the ipoint field, another thread may still see the reference of the old value.

Code Block
bgColor#FFcccc
class Holder {
  ImmutablePoint ipoint;
  
  Holder(ImmutablePoint ip) {
   ipoint = ip;
  }
  
  ImmutablePoint getPoint() {
    return ipoint;
  }

  void setPoint(ImmutablePoint ip) {
    this.ipoint = ip;
  }
}

public class ImmutablePoint {
  final int x;
  final int y;

  public ImmutablePoint(int x, int y) {
    this.x = x;
    this.y = y;
  }
}

Holder is mutable because a new ImmutablePoint instance can be assigned to it using the setPoint() method. If one thread updates the value of the ipoint field, another thread may still see the reference of the old value. This is a violation of CON28-J. Synchronize access to shared fields that refer to immutable data.

Compliant Solution (visibility)

...

Code Block
bgColor#ccccff
public class Container<K,V> {
  volatile Map<K,V> map;
  // ...
}

Alternative solutions to using volatile for safe publication are discussed in CON26-J. Do not publish partially-constructed objects.

Risk Assessment

Failing to use volatile to guarantee visibility of shared values across multiple thread and prevent reordering of statements accesses can result in unpredictable control flow.

...