Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: finished first edit/review pass

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. Consequently, this recommendation is not applicable in cases where the atomicity of composite operations must be guaranteed (see CON01-J. Do not assume that composite operations on primitive data are atomic).

...

This compliant solution qualifies the done flag as volatile so that updates by one thread are immediately visible to another threadother threads.

Code Block
bgColor#ccccff
final class ControlledStop implements Runnable {
  private volatile boolean done = false;
 
  public void run() {
    while (!done) {
      try {
        // ...
        Thread.currentThread().sleep(1000); // Do something
      } catch(InterruptedException ie) { 
        // handle exception
      } 
    } 	 
  }

  protected void shutdown(){
    done = true;
  }
}

Noncompliant Code Example (

...

non-volatile guard)

This noncompliant code example declares a non-volatile variable of type int which is initialized in the constructor depending on a security check.

...

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 (see CON09-J. Do not assume that classes having only immutable members are immutable).

Code Block
bgColor#FFcccc

class Holder {
  ImmutablePoint ipoint
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 CON09-J. Do not assume that classes having only immutable members are immutable.

Compliant Solution (visibility)

Because the ipoint field is non-volatile, changes to this value may not be immediately visible to other threads.

Compliant Solution (visibility)

This compliant solution declares the ipoint field as volatile so that updates are immediately This compliant solution declares the ipoint field as volatile so that updates are immediately visible to other threads.

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

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

Note that no synchronization is necessary for the setPoint() method The setPoint() method does not need to be synchronized because it operates atomically on immutable data, that is, on an instance of ImmutablePoint.

Declaring immutable fields as volatile enables their safe publication , in that, once published, it is impossible to change the state of the sub-object.

...

Thread-safe classes (which may not be strictly immutable), such as Container in this noncompliant code example, must not use nonfinal and nonvolatile fields to ensure that no thread sees any field references declare fields as non-final and non-volatile. Non-final, non-volatile fields may be observed by other threads before the sub-objects' initialization has concluded.

This noncompliant code example does not fails to declare the map field as volatile or final. Consequently, a thread that invokes the get() method may observe the value of the map field map before initialization has concludedbefore initialization has concluded.

Code Block
bgColor#FFcccc

public class Container<K,V> {
  Map<K,V> map;

  public synchronized void initialize() {
    if (map == null) {
      map = new HashMap<K,V>();	         
      // Fill some useful values into HashMap
    }
  }

  public V get(Object k) {
    if (map != null) {
      return map.get(k);
    } else {
      return null;
    }
  }
}

Compliant Solution (proper initialization)

This compliant solution declares the map field as volatile to ensure other threads see an up-to-date HashMap reference.

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

  public synchronized void initialize() {
    if (map == null) {
      map = new HashMap<K,V>();	         
      // Fill some useful values into HashMap
    }
  }

  public V get(Object k) {
    if(map != null) {
      return map.get(k); }

  public V } elseget(Object k) {
    if (map return!= null;) {
    }
  }
}

Compliant Solution (proper initialization)

This compliant solution declares the map field as volatile to ensure other threads see an up-to-date HashMap reference.

Code Block
bgColor#ccccff

public class Container<K,V> {
  volatile Map<K,V> map;
  // ...    return map.get(k);
    } else {
      return null;
    }
  }
}

Wiki Markup
Alternative solutions to using {{volatile}} for safe publication are discusseddescribed in [CON26-J. Do not publish partially-constructed objects]. These alternative solutions are recommended if the values of the {{map}} can be mutated after initialization because the use of {{volatile}} only guarantees "one time safe publication" \[[Goetz 06|AA. Java References#Goetz 06]\], that is the reference is made visible only after initialization. There is no guarantee that any future updates to the map's contents will be visible immediately (see [CON11-J. Do not assume that declaring an object volatile guarantees visibility of its members] for more information).

...